Set Hrtf.Moving after setting the source params instead of after mixing
[openal-soft.git] / Alc / ALu.c
blob8dee6a43b184b3005744edf04bd080594a8a0617
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 ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
110 ALfloat temp[4] = {
111 vector[0], vector[1], vector[2], w
114 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
115 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
116 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
120 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
122 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
123 static const struct ChanMap StereoMap[2] = {
124 { FrontLeft, -30.0f * F_PI/180.0f },
125 { FrontRight, 30.0f * F_PI/180.0f }
127 static const struct ChanMap StereoWideMap[2] = {
128 { FrontLeft, -90.0f * F_PI/180.0f },
129 { FrontRight, 90.0f * F_PI/180.0f }
131 static const struct ChanMap RearMap[2] = {
132 { BackLeft, -150.0f * F_PI/180.0f },
133 { BackRight, 150.0f * F_PI/180.0f }
135 static const struct ChanMap QuadMap[4] = {
136 { FrontLeft, -45.0f * F_PI/180.0f },
137 { FrontRight, 45.0f * F_PI/180.0f },
138 { BackLeft, -135.0f * F_PI/180.0f },
139 { BackRight, 135.0f * F_PI/180.0f }
141 static const struct ChanMap X51Map[6] = {
142 { FrontLeft, -30.0f * F_PI/180.0f },
143 { FrontRight, 30.0f * F_PI/180.0f },
144 { FrontCenter, 0.0f * F_PI/180.0f },
145 { LFE, 0.0f },
146 { BackLeft, -110.0f * F_PI/180.0f },
147 { BackRight, 110.0f * F_PI/180.0f }
149 static const struct ChanMap X61Map[7] = {
150 { FrontLeft, -30.0f * F_PI/180.0f },
151 { FrontRight, 30.0f * F_PI/180.0f },
152 { FrontCenter, 0.0f * F_PI/180.0f },
153 { LFE, 0.0f },
154 { BackCenter, 180.0f * F_PI/180.0f },
155 { SideLeft, -90.0f * F_PI/180.0f },
156 { SideRight, 90.0f * F_PI/180.0f }
158 static const struct ChanMap X71Map[8] = {
159 { FrontLeft, -30.0f * F_PI/180.0f },
160 { FrontRight, 30.0f * F_PI/180.0f },
161 { FrontCenter, 0.0f * F_PI/180.0f },
162 { LFE, 0.0f },
163 { BackLeft, -150.0f * F_PI/180.0f },
164 { BackRight, 150.0f * F_PI/180.0f },
165 { SideLeft, -90.0f * F_PI/180.0f },
166 { SideRight, 90.0f * F_PI/180.0f }
169 ALCdevice *Device = ALContext->Device;
170 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
171 ALbufferlistitem *BufferListItem;
172 enum FmtChannels Channels;
173 ALfloat (*SrcMatrix)[MaxChannels];
174 ALfloat DryGain, DryGainHF;
175 ALfloat WetGain[MAX_SENDS];
176 ALfloat WetGainHF[MAX_SENDS];
177 ALint NumSends, Frequency;
178 const struct ChanMap *chans = NULL;
179 enum Resampler Resampler;
180 ALint num_channels = 0;
181 ALboolean DirectChannels;
182 ALfloat hwidth = 0.0f;
183 ALfloat Pitch;
184 ALfloat cw;
185 ALint i, c;
187 /* Get device properties */
188 NumSends = Device->NumAuxSends;
189 Frequency = Device->Frequency;
191 /* Get listener properties */
192 ListenerGain = ALContext->Listener->Gain;
194 /* Get source properties */
195 SourceVolume = ALSource->Gain;
196 MinVolume = ALSource->MinGain;
197 MaxVolume = ALSource->MaxGain;
198 Pitch = ALSource->Pitch;
199 Resampler = ALSource->Resampler;
200 DirectChannels = ALSource->DirectChannels;
202 /* Calculate the stepping value */
203 Channels = FmtMono;
204 BufferListItem = ALSource->queue;
205 while(BufferListItem != NULL)
207 ALbuffer *ALBuffer;
208 if((ALBuffer=BufferListItem->buffer) != NULL)
210 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
211 maxstep -= ResamplerPadding[Resampler] +
212 ResamplerPrePadding[Resampler] + 1;
213 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
215 Pitch = Pitch * ALBuffer->Frequency / Frequency;
216 if(Pitch > (ALfloat)maxstep)
217 ALSource->Params.Step = maxstep<<FRACTIONBITS;
218 else
220 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
221 if(ALSource->Params.Step == 0)
222 ALSource->Params.Step = 1;
224 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
226 Channels = ALBuffer->FmtChannels;
227 break;
229 BufferListItem = BufferListItem->next;
231 if(!DirectChannels && Device->Hrtf)
232 ALSource->Params.DryMix = SelectHrtfMixer();
233 else
234 ALSource->Params.DryMix = SelectDirectMixer();
235 ALSource->Params.WetMix = SelectSendMixer();
237 /* Calculate gains */
238 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
239 DryGain *= ALSource->DirectGain * ListenerGain;
240 DryGainHF = ALSource->DirectGainHF;
241 for(i = 0;i < NumSends;i++)
243 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
244 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
245 WetGainHF[i] = ALSource->Send[i].GainHF;
248 SrcMatrix = ALSource->Params.Direct.Gains;
249 for(i = 0;i < MaxChannels;i++)
251 for(c = 0;c < MaxChannels;c++)
252 SrcMatrix[i][c] = 0.0f;
254 switch(Channels)
256 case FmtMono:
257 chans = MonoMap;
258 num_channels = 1;
259 break;
261 case FmtStereo:
262 if(!(Device->Flags&DEVICE_WIDE_STEREO))
263 chans = StereoMap;
264 else
266 chans = StereoWideMap;
267 hwidth = 60.0f * F_PI/180.0f;
269 num_channels = 2;
270 break;
272 case FmtRear:
273 chans = RearMap;
274 num_channels = 2;
275 break;
277 case FmtQuad:
278 chans = QuadMap;
279 num_channels = 4;
280 break;
282 case FmtX51:
283 chans = X51Map;
284 num_channels = 6;
285 break;
287 case FmtX61:
288 chans = X61Map;
289 num_channels = 7;
290 break;
292 case FmtX71:
293 chans = X71Map;
294 num_channels = 8;
295 break;
298 if(DirectChannels != AL_FALSE)
300 for(c = 0;c < num_channels;c++)
302 for(i = 0;i < (ALint)Device->NumChan;i++)
304 enum Channel chan = Device->Speaker2Chan[i];
305 if(chan == chans[c].channel)
307 SrcMatrix[c][chan] += DryGain;
308 break;
313 else if(Device->Hrtf)
315 for(c = 0;c < num_channels;c++)
317 if(chans[c].channel == LFE)
319 /* Skip LFE */
320 ALSource->Params.Direct.Hrtf.Delay[c][0] = 0;
321 ALSource->Params.Direct.Hrtf.Delay[c][1] = 0;
322 for(i = 0;i < HRIR_LENGTH;i++)
324 ALSource->Params.Direct.Hrtf.Coeffs[c][i][0] = 0.0f;
325 ALSource->Params.Direct.Hrtf.Coeffs[c][i][1] = 0.0f;
328 else
330 /* Get the static HRIR coefficients and delays for this
331 * channel. */
332 GetLerpedHrtfCoeffs(Device->Hrtf,
333 0.0f, chans[c].angle, DryGain,
334 ALSource->Params.Direct.Hrtf.Coeffs[c],
335 ALSource->Params.Direct.Hrtf.Delay[c]);
338 ALSource->Hrtf.Counter = 0;
340 else
342 DryGain *= lerp(1.0f, 1.0f/sqrtf(Device->NumChan), hwidth/(F_PI*2.0f));
343 for(c = 0;c < num_channels;c++)
345 /* Special-case LFE */
346 if(chans[c].channel == LFE)
348 SrcMatrix[c][chans[c].channel] = DryGain;
349 continue;
351 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
352 SrcMatrix[c]);
355 for(i = 0;i < NumSends;i++)
357 ALeffectslot *Slot = ALSource->Send[i].Slot;
359 if(!Slot && i == 0)
360 Slot = Device->DefaultSlot;
361 if(Slot && Slot->effect.type == AL_EFFECT_NULL)
362 Slot = NULL;
363 ALSource->Params.Send[i].Slot = Slot;
364 ALSource->Params.Send[i].Gain = WetGain[i];
367 /* Update filter coefficients. Calculations based on the I3DL2
368 * spec. */
369 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
371 /* We use two chained one-pole filters, so we need to take the
372 * square root of the squared gain, which is the same as the base
373 * gain. */
374 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
375 for(i = 0;i < NumSends;i++)
377 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
378 ALSource->Params.Send[i].iirFilter.coeff = a;
382 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
384 const ALCdevice *Device = ALContext->Device;
385 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
386 ALfloat Direction[3],Position[3],SourceToListener[3];
387 ALfloat Velocity[3],ListenerVel[3];
388 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
389 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
390 ALfloat DopplerFactor, SpeedOfSound;
391 ALfloat AirAbsorptionFactor;
392 ALfloat RoomAirAbsorption[MAX_SENDS];
393 ALbufferlistitem *BufferListItem;
394 ALfloat Attenuation;
395 ALfloat RoomAttenuation[MAX_SENDS];
396 ALfloat MetersPerUnit;
397 ALfloat RoomRolloffBase;
398 ALfloat RoomRolloff[MAX_SENDS];
399 ALfloat DecayDistance[MAX_SENDS];
400 ALfloat DryGain;
401 ALfloat DryGainHF;
402 ALboolean DryGainHFAuto;
403 ALfloat WetGain[MAX_SENDS];
404 ALfloat WetGainHF[MAX_SENDS];
405 ALboolean WetGainAuto;
406 ALboolean WetGainHFAuto;
407 enum Resampler Resampler;
408 ALfloat Matrix[4][4];
409 ALfloat Pitch;
410 ALuint Frequency;
411 ALint NumSends;
412 ALfloat cw;
413 ALint i, j;
415 DryGainHF = 1.0f;
416 for(i = 0;i < MAX_SENDS;i++)
417 WetGainHF[i] = 1.0f;
419 /* Get context/device properties */
420 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
421 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
422 NumSends = Device->NumAuxSends;
423 Frequency = Device->Frequency;
425 /* Get listener properties */
426 ListenerGain = ALContext->Listener->Gain;
427 MetersPerUnit = ALContext->Listener->MetersPerUnit;
428 ListenerVel[0] = ALContext->Listener->Velocity[0];
429 ListenerVel[1] = ALContext->Listener->Velocity[1];
430 ListenerVel[2] = ALContext->Listener->Velocity[2];
431 for(i = 0;i < 4;i++)
433 for(j = 0;j < 4;j++)
434 Matrix[i][j] = ALContext->Listener->Params.Matrix[i][j];
437 /* Get source properties */
438 SourceVolume = ALSource->Gain;
439 MinVolume = ALSource->MinGain;
440 MaxVolume = ALSource->MaxGain;
441 Pitch = ALSource->Pitch;
442 Resampler = ALSource->Resampler;
443 Position[0] = ALSource->Position[0];
444 Position[1] = ALSource->Position[1];
445 Position[2] = ALSource->Position[2];
446 Direction[0] = ALSource->Orientation[0];
447 Direction[1] = ALSource->Orientation[1];
448 Direction[2] = ALSource->Orientation[2];
449 Velocity[0] = ALSource->Velocity[0];
450 Velocity[1] = ALSource->Velocity[1];
451 Velocity[2] = ALSource->Velocity[2];
452 MinDist = ALSource->RefDistance;
453 MaxDist = ALSource->MaxDistance;
454 Rolloff = ALSource->RollOffFactor;
455 InnerAngle = ALSource->InnerAngle;
456 OuterAngle = ALSource->OuterAngle;
457 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
458 DryGainHFAuto = ALSource->DryGainHFAuto;
459 WetGainAuto = ALSource->WetGainAuto;
460 WetGainHFAuto = ALSource->WetGainHFAuto;
461 RoomRolloffBase = ALSource->RoomRolloffFactor;
462 for(i = 0;i < NumSends;i++)
464 ALeffectslot *Slot = ALSource->Send[i].Slot;
466 if(!Slot && i == 0)
467 Slot = Device->DefaultSlot;
468 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
470 Slot = NULL;
471 RoomRolloff[i] = 0.0f;
472 DecayDistance[i] = 0.0f;
473 RoomAirAbsorption[i] = 1.0f;
475 else if(Slot->AuxSendAuto)
477 RoomRolloff[i] = RoomRolloffBase;
478 if(IsReverbEffect(Slot->effect.type))
480 RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor;
481 DecayDistance[i] = Slot->effect.Reverb.DecayTime *
482 SPEEDOFSOUNDMETRESPERSEC;
483 RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF;
485 else
487 DecayDistance[i] = 0.0f;
488 RoomAirAbsorption[i] = 1.0f;
491 else
493 /* If the slot's auxiliary send auto is off, the data sent to the
494 * effect slot is the same as the dry path, sans filter effects */
495 RoomRolloff[i] = Rolloff;
496 DecayDistance[i] = 0.0f;
497 RoomAirAbsorption[i] = AIRABSORBGAINHF;
500 ALSource->Params.Send[i].Slot = Slot;
503 /* Transform source to listener space (convert to head relative) */
504 if(ALSource->HeadRelative == AL_FALSE)
506 /* Translate position */
507 Position[0] -= ALContext->Listener->Position[0];
508 Position[1] -= ALContext->Listener->Position[1];
509 Position[2] -= ALContext->Listener->Position[2];
511 /* Transform source vectors */
512 aluMatrixVector(Position, 1.0f, Matrix);
513 aluMatrixVector(Direction, 0.0f, Matrix);
514 aluMatrixVector(Velocity, 0.0f, Matrix);
515 /* Transform listener velocity */
516 aluMatrixVector(ListenerVel, 0.0f, Matrix);
518 else
520 /* Transform listener velocity from world space to listener space */
521 aluMatrixVector(ListenerVel, 0.0f, Matrix);
522 /* Offset the source velocity to be relative of the listener velocity */
523 Velocity[0] += ListenerVel[0];
524 Velocity[1] += ListenerVel[1];
525 Velocity[2] += ListenerVel[2];
528 SourceToListener[0] = -Position[0];
529 SourceToListener[1] = -Position[1];
530 SourceToListener[2] = -Position[2];
531 aluNormalize(SourceToListener);
532 aluNormalize(Direction);
534 /* Calculate distance attenuation */
535 Distance = sqrtf(aluDotproduct(Position, Position));
536 ClampedDist = Distance;
538 Attenuation = 1.0f;
539 for(i = 0;i < NumSends;i++)
540 RoomAttenuation[i] = 1.0f;
541 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
542 ALContext->DistanceModel)
544 case InverseDistanceClamped:
545 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
546 if(MaxDist < MinDist)
547 break;
548 /*fall-through*/
549 case InverseDistance:
550 if(MinDist > 0.0f)
552 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
553 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
554 for(i = 0;i < NumSends;i++)
556 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
557 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
560 break;
562 case LinearDistanceClamped:
563 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
564 if(MaxDist < MinDist)
565 break;
566 /*fall-through*/
567 case LinearDistance:
568 if(MaxDist != MinDist)
570 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
571 Attenuation = maxf(Attenuation, 0.0f);
572 for(i = 0;i < NumSends;i++)
574 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
575 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
578 break;
580 case ExponentDistanceClamped:
581 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
582 if(MaxDist < MinDist)
583 break;
584 /*fall-through*/
585 case ExponentDistance:
586 if(ClampedDist > 0.0f && MinDist > 0.0f)
588 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
589 for(i = 0;i < NumSends;i++)
590 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
592 break;
594 case DisableDistance:
595 ClampedDist = MinDist;
596 break;
599 /* Source Gain + Attenuation */
600 DryGain = SourceVolume * Attenuation;
601 for(i = 0;i < NumSends;i++)
602 WetGain[i] = SourceVolume * RoomAttenuation[i];
604 /* Distance-based air absorption */
605 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
607 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
608 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
609 for(i = 0;i < NumSends;i++)
610 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
613 if(WetGainAuto)
615 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
617 /* Apply a decay-time transformation to the wet path, based on the
618 * attenuation of the dry path.
620 * Using the apparent distance, based on the distance attenuation, the
621 * initial decay of the reverb effect is calculated and applied to the
622 * wet path.
624 for(i = 0;i < NumSends;i++)
626 if(DecayDistance[i] > 0.0f)
627 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
631 /* Calculate directional soundcones */
632 Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI);
633 if(Angle > InnerAngle && Angle <= OuterAngle)
635 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
636 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
637 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
639 else if(Angle > OuterAngle)
641 ConeVolume = ALSource->OuterGain;
642 ConeHF = ALSource->OuterGainHF;
644 else
646 ConeVolume = 1.0f;
647 ConeHF = 1.0f;
650 DryGain *= ConeVolume;
651 if(WetGainAuto)
653 for(i = 0;i < NumSends;i++)
654 WetGain[i] *= ConeVolume;
656 if(DryGainHFAuto)
657 DryGainHF *= ConeHF;
658 if(WetGainHFAuto)
660 for(i = 0;i < NumSends;i++)
661 WetGainHF[i] *= ConeHF;
664 /* Clamp to Min/Max Gain */
665 DryGain = clampf(DryGain, MinVolume, MaxVolume);
666 for(i = 0;i < NumSends;i++)
667 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
669 /* Apply gain and frequency filters */
670 DryGain *= ALSource->DirectGain * ListenerGain;
671 DryGainHF *= ALSource->DirectGainHF;
672 for(i = 0;i < NumSends;i++)
674 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
675 WetGainHF[i] *= ALSource->Send[i].GainHF;
678 /* Calculate velocity-based doppler effect */
679 if(DopplerFactor > 0.0f)
681 ALfloat VSS, VLS;
683 if(SpeedOfSound < 1.0f)
685 DopplerFactor *= 1.0f/SpeedOfSound;
686 SpeedOfSound = 1.0f;
689 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
690 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
692 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
693 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
696 BufferListItem = ALSource->queue;
697 while(BufferListItem != NULL)
699 ALbuffer *ALBuffer;
700 if((ALBuffer=BufferListItem->buffer) != NULL)
702 /* Calculate fixed-point stepping value, based on the pitch, buffer
703 * frequency, and output frequency. */
704 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
705 maxstep -= ResamplerPadding[Resampler] +
706 ResamplerPrePadding[Resampler] + 1;
707 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
709 Pitch = Pitch * ALBuffer->Frequency / Frequency;
710 if(Pitch > (ALfloat)maxstep)
711 ALSource->Params.Step = maxstep<<FRACTIONBITS;
712 else
714 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
715 if(ALSource->Params.Step == 0)
716 ALSource->Params.Step = 1;
718 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
720 break;
722 BufferListItem = BufferListItem->next;
724 if(Device->Hrtf)
725 ALSource->Params.DryMix = SelectHrtfMixer();
726 else
727 ALSource->Params.DryMix = SelectDirectMixer();
728 ALSource->Params.WetMix = SelectSendMixer();
730 if(Device->Hrtf)
732 /* Use a binaural HRTF algorithm for stereo headphone playback */
733 ALfloat delta, ev = 0.0f, az = 0.0f;
735 if(Distance > 0.0f)
737 ALfloat invlen = 1.0f/Distance;
738 Position[0] *= invlen;
739 Position[1] *= invlen;
740 Position[2] *= invlen;
742 /* Calculate elevation and azimuth only when the source is not at
743 * the listener. This prevents +0 and -0 Z from producing
744 * inconsistent panning. Also, clamp Y in case FP precision errors
745 * cause it to land outside of -1..+1. */
746 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
747 az = atan2f(Position[0], -Position[2]*ZScale);
750 /* Check to see if the HRIR is already moving. */
751 if(ALSource->Hrtf.Moving)
753 /* Calculate the normalized HRTF transition factor (delta). */
754 delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Gain, DryGain,
755 ALSource->Params.Direct.Hrtf.Dir, Position);
756 /* If the delta is large enough, get the moving HRIR target
757 * coefficients, target delays, steppping values, and counter. */
758 if(delta > 0.001f)
760 ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
761 ev, az, DryGain, delta,
762 ALSource->Hrtf.Counter,
763 ALSource->Params.Direct.Hrtf.Coeffs[0],
764 ALSource->Params.Direct.Hrtf.Delay[0],
765 ALSource->Params.Direct.Hrtf.CoeffStep,
766 ALSource->Params.Direct.Hrtf.DelayStep);
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 /* Get the initial (static) HRIR coefficients and delays. */
776 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
777 ALSource->Params.Direct.Hrtf.Coeffs[0],
778 ALSource->Params.Direct.Hrtf.Delay[0]);
779 ALSource->Hrtf.Counter = 0;
780 ALSource->Hrtf.Moving = AL_TRUE;
781 ALSource->Params.Direct.Hrtf.Gain = DryGain;
782 ALSource->Params.Direct.Hrtf.Dir[0] = Position[0];
783 ALSource->Params.Direct.Hrtf.Dir[1] = Position[1];
784 ALSource->Params.Direct.Hrtf.Dir[2] = Position[2];
787 else
789 ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
790 ALfloat DirGain = 0.0f;
791 ALfloat AmbientGain;
793 for(i = 0;i < MaxChannels;i++)
795 for(j = 0;j < MaxChannels;j++)
796 Matrix[i][j] = 0.0f;
799 /* Normalize the length, and compute panned gains. */
800 if(Distance > 0.0f)
802 ALfloat invlen = 1.0f/Distance;
803 Position[0] *= invlen;
804 Position[1] *= invlen;
805 Position[2] *= invlen;
807 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
808 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
809 DryGain*DirGain, Matrix[0]);
812 /* Adjustment for vertical offsets. Not the greatest, but simple
813 * enough. */
814 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
815 for(i = 0;i < (ALint)Device->NumChan;i++)
817 enum Channel chan = Device->Speaker2Chan[i];
818 Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
821 for(i = 0;i < NumSends;i++)
822 ALSource->Params.Send[i].Gain = WetGain[i];
824 /* Update filter coefficients. */
825 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
827 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
828 for(i = 0;i < NumSends;i++)
830 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
831 ALSource->Params.Send[i].iirFilter.coeff = a;
836 static __inline ALfloat aluF2F(ALfloat val)
837 { return val; }
838 static __inline ALint aluF2I(ALfloat val)
840 if(val > 1.0f) return 2147483647;
841 if(val < -1.0f) return -2147483647-1;
842 return fastf2i((ALfloat)(val*2147483647.0));
844 static __inline ALuint aluF2UI(ALfloat val)
845 { return aluF2I(val)+2147483648u; }
846 static __inline ALshort aluF2S(ALfloat val)
847 { return aluF2I(val)>>16; }
848 static __inline ALushort aluF2US(ALfloat val)
849 { return aluF2S(val)+32768; }
850 static __inline ALbyte aluF2B(ALfloat val)
851 { return aluF2I(val)>>24; }
852 static __inline ALubyte aluF2UB(ALfloat val)
853 { return aluF2B(val)+128; }
855 #define DECL_TEMPLATE(T, func) \
856 static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \
857 ALuint SamplesToDo) \
859 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
860 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
861 const enum Channel *ChanMap = device->DevChannels; \
862 ALuint i, j; \
864 for(j = 0;j < numchans;j++) \
866 T *RESTRICT out = buffer + j; \
867 enum Channel chan = ChanMap[j]; \
869 for(i = 0;i < SamplesToDo;i++) \
870 out[i*numchans] = func(DryBuffer[chan][i]); \
872 return SamplesToDo*numchans*sizeof(T); \
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 if(UpdateSources)
915 ALlistener *listener = ctx->Listener;
916 ALfloat N[3], V[3], U[3];
917 /* AT then UP */
918 N[0] = listener->Forward[0];
919 N[1] = listener->Forward[1];
920 N[2] = listener->Forward[2];
921 aluNormalize(N);
922 V[0] = listener->Up[0];
923 V[1] = listener->Up[1];
924 V[2] = listener->Up[1];
925 aluNormalize(V);
926 /* Build and normalize right-vector */
927 aluCrossproduct(N, V, U);
928 aluNormalize(U);
930 listener->Params.Matrix[0][0] = U[0];
931 listener->Params.Matrix[0][1] = V[0];
932 listener->Params.Matrix[0][2] = -N[0];
933 listener->Params.Matrix[0][3] = 0.0f;
934 listener->Params.Matrix[1][0] = U[1];
935 listener->Params.Matrix[1][1] = V[1];
936 listener->Params.Matrix[1][2] = -N[1];
937 listener->Params.Matrix[1][3] = 0.0f;
938 listener->Params.Matrix[2][0] = U[2];
939 listener->Params.Matrix[2][1] = V[2];
940 listener->Params.Matrix[2][2] = -N[2];
941 listener->Params.Matrix[2][3] = 0.0f;
942 listener->Params.Matrix[3][0] = 0.0f;
943 listener->Params.Matrix[3][1] = 0.0f;
944 listener->Params.Matrix[3][2] = 0.0f;
945 listener->Params.Matrix[3][3] = 1.0f;
948 /* source processing */
949 src = ctx->ActiveSources;
950 src_end = src + ctx->ActiveSourceCount;
951 while(src != src_end)
953 if((*src)->state != AL_PLAYING)
955 --(ctx->ActiveSourceCount);
956 *src = *(--src_end);
957 continue;
960 if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
961 UpdateSources))
962 ALsource_Update(*src, ctx);
964 MixSource(*src, device, SamplesToDo);
965 src++;
968 /* effect slot processing */
969 slot = ctx->ActiveEffectSlots;
970 slot_end = slot + ctx->ActiveEffectSlotCount;
971 while(slot != slot_end)
973 ALfloat offset = (*slot)->ClickRemoval[0];
974 if(offset < (1.0f/32768.0f))
975 offset = 0.0f;
976 else for(i = 0;i < SamplesToDo;i++)
978 (*slot)->WetBuffer[0][i] += offset;
979 offset -= offset * (1.0f/256.0f);
981 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
982 (*slot)->PendingClicks[0] = 0.0f;
984 if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
985 ALeffectState_Update((*slot)->EffectState, device, *slot);
987 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
988 (*slot)->WetBuffer[0], device->DryBuffer);
990 for(i = 0;i < SamplesToDo;i++)
991 (*slot)->WetBuffer[0][i] = 0.0f;
993 slot++;
996 ctx = ctx->next;
999 slot = &device->DefaultSlot;
1000 if(*slot != NULL)
1002 ALfloat offset = (*slot)->ClickRemoval[0];
1003 if(offset < (1.0f/32768.0f))
1004 offset = 0.0f;
1005 else for(i = 0;i < SamplesToDo;i++)
1007 (*slot)->WetBuffer[0][i] += offset;
1008 offset -= offset * (1.0f/256.0f);
1010 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
1011 (*slot)->PendingClicks[0] = 0.0f;
1013 if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
1014 ALeffectState_Update((*slot)->EffectState, device, *slot);
1016 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
1017 (*slot)->WetBuffer[0], device->DryBuffer);
1019 for(i = 0;i < SamplesToDo;i++)
1020 (*slot)->WetBuffer[0][i] = 0.0f;
1022 ALCdevice_Unlock(device);
1024 /* Click-removal. Could do better; this only really handles immediate
1025 * changes between updates where a predictive sample could be
1026 * generated. Delays caused by effects and HRTF aren't caught. */
1027 if(device->FmtChans == DevFmtMono)
1029 ALfloat offset = device->ClickRemoval[FrontCenter];
1030 if(offset < (1.0f/32768.0f))
1031 offset = 0.0f;
1032 else for(i = 0;i < SamplesToDo;i++)
1034 device->DryBuffer[FrontCenter][i] += offset;
1035 offset -= offset * (1.0f/256.0f);
1037 device->ClickRemoval[FrontCenter] = offset + device->PendingClicks[FrontCenter];
1038 device->PendingClicks[FrontCenter] = 0.0f;
1040 else if(device->FmtChans == DevFmtStereo)
1042 /* Assumes the first two channels are FrontLeft and FrontRight */
1043 for(c = 0;c < 2;c++)
1045 ALfloat offset = device->ClickRemoval[c];
1046 if(offset < (1.0f/32768.0f))
1047 offset = 0.0f;
1048 else for(i = 0;i < SamplesToDo;i++)
1050 device->DryBuffer[c][i] += offset;
1051 offset -= offset * (1.0f/256.0f);
1053 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1054 device->PendingClicks[c] = 0.0f;
1056 if(device->Bs2b)
1058 float samples[2];
1059 for(i = 0;i < SamplesToDo;i++)
1061 samples[0] = device->DryBuffer[FrontLeft][i];
1062 samples[1] = device->DryBuffer[FrontRight][i];
1063 bs2b_cross_feed(device->Bs2b, samples);
1064 device->DryBuffer[FrontLeft][i] = samples[0];
1065 device->DryBuffer[FrontRight][i] = samples[1];
1069 else
1071 for(c = 0;c < MaxChannels;c++)
1073 ALfloat offset = device->ClickRemoval[c];
1074 if(offset < (1.0f/32768.0f))
1075 offset = 0.0f;
1076 else for(i = 0;i < SamplesToDo;i++)
1078 device->DryBuffer[c][i] += offset;
1079 offset -= offset * (1.0f/256.0f);
1081 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1082 device->PendingClicks[c] = 0.0f;
1086 if(buffer)
1088 int bytes = 0;
1089 switch(device->FmtType)
1091 case DevFmtByte:
1092 bytes = Write_ALbyte(device, buffer, SamplesToDo);
1093 break;
1094 case DevFmtUByte:
1095 bytes = Write_ALubyte(device, buffer, SamplesToDo);
1096 break;
1097 case DevFmtShort:
1098 bytes = Write_ALshort(device, buffer, SamplesToDo);
1099 break;
1100 case DevFmtUShort:
1101 bytes = Write_ALushort(device, buffer, SamplesToDo);
1102 break;
1103 case DevFmtInt:
1104 bytes = Write_ALint(device, buffer, SamplesToDo);
1105 break;
1106 case DevFmtUInt:
1107 bytes = Write_ALuint(device, buffer, SamplesToDo);
1108 break;
1109 case DevFmtFloat:
1110 bytes = Write_ALfloat(device, buffer, SamplesToDo);
1111 break;
1114 buffer = (ALubyte*)buffer + bytes;
1117 size -= SamplesToDo;
1120 RestoreFPUMode(&oldMode);
1124 ALvoid aluHandleDisconnect(ALCdevice *device)
1126 ALCcontext *Context;
1128 ALCdevice_Lock(device);
1129 device->Connected = ALC_FALSE;
1131 Context = device->ContextList;
1132 while(Context)
1134 ALsource **src, **src_end;
1136 src = Context->ActiveSources;
1137 src_end = src + Context->ActiveSourceCount;
1138 while(src != src_end)
1140 if((*src)->state == AL_PLAYING)
1142 (*src)->state = AL_STOPPED;
1143 (*src)->BuffersPlayed = (*src)->BuffersInQueue;
1144 (*src)->position = 0;
1145 (*src)->position_fraction = 0;
1147 src++;
1149 Context->ActiveSourceCount = 0;
1151 Context = Context->next;
1153 ALCdevice_Unlock(device);