Mostly load into fontsound objects directly
[openal-soft.git] / Alc / ALu.c
blob34ac6687f083ae635b53ff74c268a975a5fd37d8
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"
39 #include "midi/base.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;
53 extern inline ALfloat minf(ALfloat a, ALfloat b);
54 extern inline ALfloat maxf(ALfloat a, ALfloat b);
55 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
57 extern inline ALdouble mind(ALdouble a, ALdouble b);
58 extern inline ALdouble maxd(ALdouble a, ALdouble b);
59 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
61 extern inline ALuint minu(ALuint a, ALuint b);
62 extern inline ALuint maxu(ALuint a, ALuint b);
63 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
65 extern inline ALint mini(ALint a, ALint b);
66 extern inline ALint maxi(ALint a, ALint b);
67 extern inline ALint clampi(ALint val, ALint min, ALint max);
69 extern inline ALint64 mini64(ALint64 a, ALint64 b);
70 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
71 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
73 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
74 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
75 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
77 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
78 extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
80 static ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
82 if(increment == FRACTIONONE)
83 return Resample_copy32_C;
84 switch(Resampler)
86 case PointResampler:
87 return Resample_point32_C;
88 case LinearResampler:
89 return Resample_lerp32_C;
90 case CubicResampler:
91 return Resample_cubic32_C;
92 case ResamplerMax:
93 /* Shouldn't happen */
94 break;
97 return Resample_point32_C;
101 static DryMixerFunc SelectHrtfMixer(void)
103 #ifdef HAVE_SSE
104 if((CPUCapFlags&CPU_CAP_SSE))
105 return MixDirect_Hrtf_SSE;
106 #endif
107 #ifdef HAVE_NEON
108 if((CPUCapFlags&CPU_CAP_NEON))
109 return MixDirect_Hrtf_Neon;
110 #endif
112 return MixDirect_Hrtf_C;
115 static DryMixerFunc SelectDirectMixer(void)
117 #ifdef HAVE_SSE
118 if((CPUCapFlags&CPU_CAP_SSE))
119 return MixDirect_SSE;
120 #endif
122 return MixDirect_C;
125 static WetMixerFunc SelectSendMixer(void)
127 #ifdef HAVE_SSE
128 if((CPUCapFlags&CPU_CAP_SSE))
129 return MixSend_SSE;
130 #endif
132 return MixSend_C;
136 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
138 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
139 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
140 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
143 static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
145 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
146 inVector1[2]*inVector2[2];
149 static inline void aluNormalize(ALfloat *inVector)
151 ALfloat lengthsqr = aluDotproduct(inVector, inVector);
152 if(lengthsqr > 0.0f)
154 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
155 inVector[0] *= inv_length;
156 inVector[1] *= inv_length;
157 inVector[2] *= inv_length;
161 static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
163 ALfloat temp[4] = {
164 vector[0], vector[1], vector[2], w
167 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
168 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
169 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
173 static ALvoid CalcListenerParams(ALlistener *Listener)
175 ALfloat N[3], V[3], U[3], P[3];
177 /* AT then UP */
178 N[0] = Listener->Forward[0];
179 N[1] = Listener->Forward[1];
180 N[2] = Listener->Forward[2];
181 aluNormalize(N);
182 V[0] = Listener->Up[0];
183 V[1] = Listener->Up[1];
184 V[2] = Listener->Up[2];
185 aluNormalize(V);
186 /* Build and normalize right-vector */
187 aluCrossproduct(N, V, U);
188 aluNormalize(U);
190 Listener->Params.Matrix[0][0] = U[0];
191 Listener->Params.Matrix[0][1] = V[0];
192 Listener->Params.Matrix[0][2] = -N[0];
193 Listener->Params.Matrix[0][3] = 0.0f;
194 Listener->Params.Matrix[1][0] = U[1];
195 Listener->Params.Matrix[1][1] = V[1];
196 Listener->Params.Matrix[1][2] = -N[1];
197 Listener->Params.Matrix[1][3] = 0.0f;
198 Listener->Params.Matrix[2][0] = U[2];
199 Listener->Params.Matrix[2][1] = V[2];
200 Listener->Params.Matrix[2][2] = -N[2];
201 Listener->Params.Matrix[2][3] = 0.0f;
202 Listener->Params.Matrix[3][0] = 0.0f;
203 Listener->Params.Matrix[3][1] = 0.0f;
204 Listener->Params.Matrix[3][2] = 0.0f;
205 Listener->Params.Matrix[3][3] = 1.0f;
207 P[0] = Listener->Position[0];
208 P[1] = Listener->Position[1];
209 P[2] = Listener->Position[2];
210 aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
211 Listener->Params.Matrix[3][0] = -P[0];
212 Listener->Params.Matrix[3][1] = -P[1];
213 Listener->Params.Matrix[3][2] = -P[2];
215 Listener->Params.Velocity[0] = Listener->Velocity[0];
216 Listener->Params.Velocity[1] = Listener->Velocity[1];
217 Listener->Params.Velocity[2] = Listener->Velocity[2];
218 aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
221 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
223 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
224 static const struct ChanMap StereoMap[2] = {
225 { FrontLeft, DEG2RAD(-30.0f) },
226 { FrontRight, DEG2RAD( 30.0f) }
228 static const struct ChanMap StereoWideMap[2] = {
229 { FrontLeft, DEG2RAD(-90.0f) },
230 { FrontRight, DEG2RAD( 90.0f) }
232 static const struct ChanMap RearMap[2] = {
233 { BackLeft, DEG2RAD(-150.0f) },
234 { BackRight, DEG2RAD( 150.0f) }
236 static const struct ChanMap QuadMap[4] = {
237 { FrontLeft, DEG2RAD( -45.0f) },
238 { FrontRight, DEG2RAD( 45.0f) },
239 { BackLeft, DEG2RAD(-135.0f) },
240 { BackRight, DEG2RAD( 135.0f) }
242 static const struct ChanMap X51Map[6] = {
243 { FrontLeft, DEG2RAD( -30.0f) },
244 { FrontRight, DEG2RAD( 30.0f) },
245 { FrontCenter, DEG2RAD( 0.0f) },
246 { LFE, 0.0f },
247 { BackLeft, DEG2RAD(-110.0f) },
248 { BackRight, DEG2RAD( 110.0f) }
250 static const struct ChanMap X61Map[7] = {
251 { FrontLeft, DEG2RAD(-30.0f) },
252 { FrontRight, DEG2RAD( 30.0f) },
253 { FrontCenter, DEG2RAD( 0.0f) },
254 { LFE, 0.0f },
255 { BackCenter, DEG2RAD(180.0f) },
256 { SideLeft, DEG2RAD(-90.0f) },
257 { SideRight, DEG2RAD( 90.0f) }
259 static const struct ChanMap X71Map[8] = {
260 { FrontLeft, DEG2RAD( -30.0f) },
261 { FrontRight, DEG2RAD( 30.0f) },
262 { FrontCenter, DEG2RAD( 0.0f) },
263 { LFE, 0.0f },
264 { BackLeft, DEG2RAD(-150.0f) },
265 { BackRight, DEG2RAD( 150.0f) },
266 { SideLeft, DEG2RAD( -90.0f) },
267 { SideRight, DEG2RAD( 90.0f) }
270 ALCdevice *Device = ALContext->Device;
271 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
272 ALbufferlistitem *BufferListItem;
273 enum FmtChannels Channels;
274 ALfloat (*SrcMatrix)[MaxChannels];
275 ALfloat DryGain, DryGainHF;
276 ALfloat WetGain[MAX_SENDS];
277 ALfloat WetGainHF[MAX_SENDS];
278 ALint NumSends, Frequency;
279 const struct ChanMap *chans = NULL;
280 enum Resampler Resampler;
281 ALint num_channels = 0;
282 ALboolean DirectChannels;
283 ALfloat hwidth = 0.0f;
284 ALfloat Pitch;
285 ALint i, c;
287 /* Get device properties */
288 NumSends = Device->NumAuxSends;
289 Frequency = Device->Frequency;
291 /* Get listener properties */
292 ListenerGain = ALContext->Listener->Gain;
294 /* Get source properties */
295 SourceVolume = ALSource->Gain;
296 MinVolume = ALSource->MinGain;
297 MaxVolume = ALSource->MaxGain;
298 Pitch = ALSource->Pitch;
299 Resampler = ALSource->Resampler;
300 DirectChannels = ALSource->DirectChannels;
302 /* Calculate the stepping value */
303 Channels = FmtMono;
304 BufferListItem = ALSource->queue;
305 while(BufferListItem != NULL)
307 ALbuffer *ALBuffer;
308 if((ALBuffer=BufferListItem->buffer) != NULL)
310 Pitch = Pitch * ALBuffer->Frequency / Frequency;
311 if(Pitch > 10.0f)
312 ALSource->Params.Step = 10<<FRACTIONBITS;
313 else
315 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
316 if(ALSource->Params.Step == 0)
317 ALSource->Params.Step = 1;
319 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
321 Channels = ALBuffer->FmtChannels;
322 break;
324 BufferListItem = BufferListItem->next;
326 if(!DirectChannels && Device->Hrtf)
327 ALSource->Params.DryMix = SelectHrtfMixer();
328 else
329 ALSource->Params.DryMix = SelectDirectMixer();
330 ALSource->Params.WetMix = SelectSendMixer();
332 /* Calculate gains */
333 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
334 DryGain *= ALSource->DirectGain * ListenerGain;
335 DryGainHF = ALSource->DirectGainHF;
336 for(i = 0;i < NumSends;i++)
338 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
339 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
340 WetGainHF[i] = ALSource->Send[i].GainHF;
343 SrcMatrix = ALSource->Params.Direct.Gains;
344 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
346 for(c = 0;c < MaxChannels;c++)
347 SrcMatrix[i][c] = 0.0f;
349 switch(Channels)
351 case FmtMono:
352 chans = MonoMap;
353 num_channels = 1;
354 break;
356 case FmtStereo:
357 if(!(Device->Flags&DEVICE_WIDE_STEREO))
359 /* HACK: Place the stereo channels at +/-90 degrees when using non-
360 * HRTF stereo output. This helps reduce the "monoization" caused
361 * by them panning towards the center. */
362 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
363 chans = StereoWideMap;
364 else
365 chans = StereoMap;
367 else
369 chans = StereoWideMap;
370 hwidth = DEG2RAD(60.0f);
372 num_channels = 2;
373 break;
375 case FmtRear:
376 chans = RearMap;
377 num_channels = 2;
378 break;
380 case FmtQuad:
381 chans = QuadMap;
382 num_channels = 4;
383 break;
385 case FmtX51:
386 chans = X51Map;
387 num_channels = 6;
388 break;
390 case FmtX61:
391 chans = X61Map;
392 num_channels = 7;
393 break;
395 case FmtX71:
396 chans = X71Map;
397 num_channels = 8;
398 break;
401 if(DirectChannels != AL_FALSE)
403 for(c = 0;c < num_channels;c++)
405 for(i = 0;i < (ALint)Device->NumChan;i++)
407 enum Channel chan = Device->Speaker2Chan[i];
408 if(chan == chans[c].channel)
410 SrcMatrix[c][chan] = DryGain;
411 break;
416 else if(Device->Hrtf)
418 for(c = 0;c < num_channels;c++)
420 if(chans[c].channel == LFE)
422 /* Skip LFE */
423 ALSource->Params.Direct.Hrtf.Params.Delay[c][0] = 0;
424 ALSource->Params.Direct.Hrtf.Params.Delay[c][1] = 0;
425 for(i = 0;i < HRIR_LENGTH;i++)
427 ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][0] = 0.0f;
428 ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][1] = 0.0f;
431 else
433 /* Get the static HRIR coefficients and delays for this
434 * channel. */
435 GetLerpedHrtfCoeffs(Device->Hrtf,
436 0.0f, chans[c].angle, DryGain,
437 ALSource->Params.Direct.Hrtf.Params.Coeffs[c],
438 ALSource->Params.Direct.Hrtf.Params.Delay[c]);
441 ALSource->Hrtf.Counter = 0;
442 ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
444 ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
446 else
448 DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
449 for(c = 0;c < num_channels;c++)
451 /* Special-case LFE */
452 if(chans[c].channel == LFE)
454 SrcMatrix[c][chans[c].channel] = DryGain;
455 continue;
457 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
458 SrcMatrix[c]);
462 ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
463 ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
464 ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
465 for(i = 0;i < NumSends;i++)
467 ALeffectslot *Slot = ALSource->Send[i].Slot;
468 if(!Slot && i == 0)
469 Slot = Device->DefaultSlot;
470 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
472 ALSource->Params.Send[i].OutBuffer = NULL;
473 ALSource->Params.Send[i].ClickRemoval = NULL;
474 ALSource->Params.Send[i].PendingClicks = NULL;
476 else
478 ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
479 ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
480 ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
482 ALSource->Params.Send[i].Gain = WetGain[i];
486 ALfloat gain = maxf(0.01f, DryGainHF);
487 for(c = 0;c < num_channels;c++)
488 ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[c],
489 ALfilterType_HighShelf, gain,
490 (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
492 for(i = 0;i < NumSends;i++)
494 ALfloat gain = maxf(0.01f, WetGainHF[i]);
495 for(c = 0;c < num_channels;c++)
496 ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[c],
497 ALfilterType_HighShelf, gain,
498 (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
502 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
504 ALCdevice *Device = ALContext->Device;
505 ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
506 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
507 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
508 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
509 ALfloat DopplerFactor, SpeedOfSound;
510 ALfloat AirAbsorptionFactor;
511 ALfloat RoomAirAbsorption[MAX_SENDS];
512 ALbufferlistitem *BufferListItem;
513 ALfloat Attenuation;
514 ALfloat RoomAttenuation[MAX_SENDS];
515 ALfloat MetersPerUnit;
516 ALfloat RoomRolloffBase;
517 ALfloat RoomRolloff[MAX_SENDS];
518 ALfloat DecayDistance[MAX_SENDS];
519 ALfloat DryGain;
520 ALfloat DryGainHF;
521 ALboolean DryGainHFAuto;
522 ALfloat WetGain[MAX_SENDS];
523 ALfloat WetGainHF[MAX_SENDS];
524 ALboolean WetGainAuto;
525 ALboolean WetGainHFAuto;
526 enum Resampler Resampler;
527 ALfloat Pitch;
528 ALuint Frequency;
529 ALint NumSends;
530 ALint i, j;
532 DryGainHF = 1.0f;
533 for(i = 0;i < MAX_SENDS;i++)
534 WetGainHF[i] = 1.0f;
536 /* Get context/device properties */
537 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
538 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
539 NumSends = Device->NumAuxSends;
540 Frequency = Device->Frequency;
542 /* Get listener properties */
543 ListenerGain = ALContext->Listener->Gain;
544 MetersPerUnit = ALContext->Listener->MetersPerUnit;
546 /* Get source properties */
547 SourceVolume = ALSource->Gain;
548 MinVolume = ALSource->MinGain;
549 MaxVolume = ALSource->MaxGain;
550 Pitch = ALSource->Pitch;
551 Resampler = ALSource->Resampler;
552 Position[0] = ALSource->Position[0];
553 Position[1] = ALSource->Position[1];
554 Position[2] = ALSource->Position[2];
555 Direction[0] = ALSource->Orientation[0];
556 Direction[1] = ALSource->Orientation[1];
557 Direction[2] = ALSource->Orientation[2];
558 Velocity[0] = ALSource->Velocity[0];
559 Velocity[1] = ALSource->Velocity[1];
560 Velocity[2] = ALSource->Velocity[2];
561 MinDist = ALSource->RefDistance;
562 MaxDist = ALSource->MaxDistance;
563 Rolloff = ALSource->RollOffFactor;
564 InnerAngle = ALSource->InnerAngle;
565 OuterAngle = ALSource->OuterAngle;
566 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
567 DryGainHFAuto = ALSource->DryGainHFAuto;
568 WetGainAuto = ALSource->WetGainAuto;
569 WetGainHFAuto = ALSource->WetGainHFAuto;
570 RoomRolloffBase = ALSource->RoomRolloffFactor;
572 ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
573 ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
574 ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
575 for(i = 0;i < NumSends;i++)
577 ALeffectslot *Slot = ALSource->Send[i].Slot;
579 if(!Slot && i == 0)
580 Slot = Device->DefaultSlot;
581 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
583 Slot = NULL;
584 RoomRolloff[i] = 0.0f;
585 DecayDistance[i] = 0.0f;
586 RoomAirAbsorption[i] = 1.0f;
588 else if(Slot->AuxSendAuto)
590 RoomRolloff[i] = RoomRolloffBase;
591 if(IsReverbEffect(Slot->EffectType))
593 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
594 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
595 SPEEDOFSOUNDMETRESPERSEC;
596 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
598 else
600 DecayDistance[i] = 0.0f;
601 RoomAirAbsorption[i] = 1.0f;
604 else
606 /* If the slot's auxiliary send auto is off, the data sent to the
607 * effect slot is the same as the dry path, sans filter effects */
608 RoomRolloff[i] = Rolloff;
609 DecayDistance[i] = 0.0f;
610 RoomAirAbsorption[i] = AIRABSORBGAINHF;
613 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
615 ALSource->Params.Send[i].OutBuffer = NULL;
616 ALSource->Params.Send[i].ClickRemoval = NULL;
617 ALSource->Params.Send[i].PendingClicks = NULL;
619 else
621 ALSource->Params.Send[i].OutBuffer = Slot->WetBuffer;
622 ALSource->Params.Send[i].ClickRemoval = Slot->ClickRemoval;
623 ALSource->Params.Send[i].PendingClicks = Slot->PendingClicks;
627 /* Transform source to listener space (convert to head relative) */
628 if(ALSource->HeadRelative == AL_FALSE)
630 ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
631 /* Transform source vectors */
632 aluMatrixVector(Position, 1.0f, Matrix);
633 aluMatrixVector(Direction, 0.0f, Matrix);
634 aluMatrixVector(Velocity, 0.0f, Matrix);
636 else
638 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
639 /* Offset the source velocity to be relative of the listener velocity */
640 Velocity[0] += ListenerVel[0];
641 Velocity[1] += ListenerVel[1];
642 Velocity[2] += ListenerVel[2];
645 SourceToListener[0] = -Position[0];
646 SourceToListener[1] = -Position[1];
647 SourceToListener[2] = -Position[2];
648 aluNormalize(SourceToListener);
649 aluNormalize(Direction);
651 /* Calculate distance attenuation */
652 Distance = sqrtf(aluDotproduct(Position, Position));
653 ClampedDist = Distance;
655 Attenuation = 1.0f;
656 for(i = 0;i < NumSends;i++)
657 RoomAttenuation[i] = 1.0f;
658 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
659 ALContext->DistanceModel)
661 case InverseDistanceClamped:
662 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
663 if(MaxDist < MinDist)
664 break;
665 /*fall-through*/
666 case InverseDistance:
667 if(MinDist > 0.0f)
669 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
670 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
671 for(i = 0;i < NumSends;i++)
673 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
674 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
677 break;
679 case LinearDistanceClamped:
680 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
681 if(MaxDist < MinDist)
682 break;
683 /*fall-through*/
684 case LinearDistance:
685 if(MaxDist != MinDist)
687 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
688 Attenuation = maxf(Attenuation, 0.0f);
689 for(i = 0;i < NumSends;i++)
691 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
692 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
695 break;
697 case ExponentDistanceClamped:
698 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
699 if(MaxDist < MinDist)
700 break;
701 /*fall-through*/
702 case ExponentDistance:
703 if(ClampedDist > 0.0f && MinDist > 0.0f)
705 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
706 for(i = 0;i < NumSends;i++)
707 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
709 break;
711 case DisableDistance:
712 ClampedDist = MinDist;
713 break;
716 /* Source Gain + Attenuation */
717 DryGain = SourceVolume * Attenuation;
718 for(i = 0;i < NumSends;i++)
719 WetGain[i] = SourceVolume * RoomAttenuation[i];
721 /* Distance-based air absorption */
722 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
724 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
725 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
726 for(i = 0;i < NumSends;i++)
727 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
730 if(WetGainAuto)
732 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
734 /* Apply a decay-time transformation to the wet path, based on the
735 * attenuation of the dry path.
737 * Using the apparent distance, based on the distance attenuation, the
738 * initial decay of the reverb effect is calculated and applied to the
739 * wet path.
741 for(i = 0;i < NumSends;i++)
743 if(DecayDistance[i] > 0.0f)
744 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
748 /* Calculate directional soundcones */
749 Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
750 if(Angle > InnerAngle && Angle <= OuterAngle)
752 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
753 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
754 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
756 else if(Angle > OuterAngle)
758 ConeVolume = ALSource->OuterGain;
759 ConeHF = ALSource->OuterGainHF;
761 else
763 ConeVolume = 1.0f;
764 ConeHF = 1.0f;
767 DryGain *= ConeVolume;
768 if(WetGainAuto)
770 for(i = 0;i < NumSends;i++)
771 WetGain[i] *= ConeVolume;
773 if(DryGainHFAuto)
774 DryGainHF *= ConeHF;
775 if(WetGainHFAuto)
777 for(i = 0;i < NumSends;i++)
778 WetGainHF[i] *= ConeHF;
781 /* Clamp to Min/Max Gain */
782 DryGain = clampf(DryGain, MinVolume, MaxVolume);
783 for(i = 0;i < NumSends;i++)
784 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
786 /* Apply gain and frequency filters */
787 DryGain *= ALSource->DirectGain * ListenerGain;
788 DryGainHF *= ALSource->DirectGainHF;
789 for(i = 0;i < NumSends;i++)
791 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
792 WetGainHF[i] *= ALSource->Send[i].GainHF;
795 /* Calculate velocity-based doppler effect */
796 if(DopplerFactor > 0.0f)
798 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
799 ALfloat VSS, VLS;
801 if(SpeedOfSound < 1.0f)
803 DopplerFactor *= 1.0f/SpeedOfSound;
804 SpeedOfSound = 1.0f;
807 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
808 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
810 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
811 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
814 BufferListItem = ALSource->queue;
815 while(BufferListItem != NULL)
817 ALbuffer *ALBuffer;
818 if((ALBuffer=BufferListItem->buffer) != NULL)
820 /* Calculate fixed-point stepping value, based on the pitch, buffer
821 * frequency, and output frequency. */
822 Pitch = Pitch * ALBuffer->Frequency / Frequency;
823 if(Pitch > 10.0f)
824 ALSource->Params.Step = 10<<FRACTIONBITS;
825 else
827 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
828 if(ALSource->Params.Step == 0)
829 ALSource->Params.Step = 1;
831 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
833 break;
835 BufferListItem = BufferListItem->next;
837 if(Device->Hrtf)
838 ALSource->Params.DryMix = SelectHrtfMixer();
839 else
840 ALSource->Params.DryMix = SelectDirectMixer();
841 ALSource->Params.WetMix = SelectSendMixer();
843 if(Device->Hrtf)
845 /* Use a binaural HRTF algorithm for stereo headphone playback */
846 ALfloat delta, ev = 0.0f, az = 0.0f;
848 if(Distance > FLT_EPSILON)
850 ALfloat invlen = 1.0f/Distance;
851 Position[0] *= invlen;
852 Position[1] *= invlen;
853 Position[2] *= invlen;
855 /* Calculate elevation and azimuth only when the source is not at
856 * the listener. This prevents +0 and -0 Z from producing
857 * inconsistent panning. Also, clamp Y in case FP precision errors
858 * cause it to land outside of -1..+1. */
859 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
860 az = atan2f(Position[0], -Position[2]*ZScale);
863 /* Check to see if the HRIR is already moving. */
864 if(ALSource->Hrtf.Moving)
866 /* Calculate the normalized HRTF transition factor (delta). */
867 delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Params.Gain, DryGain,
868 ALSource->Params.Direct.Hrtf.Params.Dir, Position);
869 /* If the delta is large enough, get the moving HRIR target
870 * coefficients, target delays, steppping values, and counter. */
871 if(delta > 0.001f)
873 ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
874 ev, az, DryGain, delta,
875 ALSource->Hrtf.Counter,
876 ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
877 ALSource->Params.Direct.Hrtf.Params.Delay[0],
878 ALSource->Params.Direct.Hrtf.Params.CoeffStep,
879 ALSource->Params.Direct.Hrtf.Params.DelayStep);
880 ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
881 ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
882 ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
883 ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
886 else
888 /* Get the initial (static) HRIR coefficients and delays. */
889 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
890 ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
891 ALSource->Params.Direct.Hrtf.Params.Delay[0]);
892 ALSource->Hrtf.Counter = 0;
893 ALSource->Hrtf.Moving = AL_TRUE;
894 ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
895 ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
896 ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
897 ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
899 ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
901 ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
903 else
905 ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
906 ALfloat DirGain = 0.0f;
907 ALfloat AmbientGain;
909 for(i = 0;i < MAX_INPUT_CHANNELS;i++)
911 for(j = 0;j < MaxChannels;j++)
912 Matrix[i][j] = 0.0f;
915 /* Normalize the length, and compute panned gains. */
916 if(Distance > FLT_EPSILON)
918 ALfloat invlen = 1.0f/Distance;
919 Position[0] *= invlen;
920 Position[1] *= invlen;
921 Position[2] *= invlen;
923 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
924 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
925 DryGain*DirGain, Matrix[0]);
928 /* Adjustment for vertical offsets. Not the greatest, but simple
929 * enough. */
930 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
931 for(i = 0;i < (ALint)Device->NumChan;i++)
933 enum Channel chan = Device->Speaker2Chan[i];
934 Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
937 for(i = 0;i < NumSends;i++)
938 ALSource->Params.Send[i].Gain = WetGain[i];
942 ALfloat gain = maxf(0.01f, DryGainHF);
943 ALfilterState_setParams(&ALSource->Params.Direct.LpFilter[0],
944 ALfilterType_HighShelf, gain,
945 (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
947 for(i = 0;i < NumSends;i++)
949 ALfloat gain = maxf(0.01f, WetGainHF[i]);
950 ALfilterState_setParams(&ALSource->Params.Send[i].LpFilter[0],
951 ALfilterType_HighShelf, gain,
952 (ALfloat)LOWPASSFREQREF/Frequency, 0.0f);
957 static inline ALint aluF2I25(ALfloat val)
959 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
960 if(fabsf(val) > 1.0f)
961 val = (ALfloat)((0.0f < val) - (val < 0.0f));
962 /* Convert to a signed integer, between -16777215 and +16777215. */
963 return fastf2i(val*16777215.0f);
966 static inline ALfloat aluF2F(ALfloat val)
967 { return val; }
968 static inline ALint aluF2I(ALfloat val)
969 { return aluF2I25(val)<<7; }
970 static inline ALuint aluF2UI(ALfloat val)
971 { return aluF2I(val)+2147483648u; }
972 static inline ALshort aluF2S(ALfloat val)
973 { return aluF2I25(val)>>9; }
974 static inline ALushort aluF2US(ALfloat val)
975 { return aluF2S(val)+32768; }
976 static inline ALbyte aluF2B(ALfloat val)
977 { return aluF2I25(val)>>17; }
978 static inline ALubyte aluF2UB(ALfloat val)
979 { return aluF2B(val)+128; }
981 #define DECL_TEMPLATE(T, func) \
982 static int Write_##T(ALCdevice *device, T *restrict buffer, \
983 ALuint SamplesToDo) \
985 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
986 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
987 const ALuint *offsets = device->ChannelOffsets; \
988 ALuint i, j; \
990 for(j = 0;j < MaxChannels;j++) \
992 T *restrict out; \
994 if(offsets[j] == INVALID_OFFSET) \
995 continue; \
997 out = buffer + offsets[j]; \
998 for(i = 0;i < SamplesToDo;i++) \
999 out[i*numchans] = func(DryBuffer[j][i]); \
1001 return SamplesToDo*numchans*sizeof(T); \
1004 DECL_TEMPLATE(ALfloat, aluF2F)
1005 DECL_TEMPLATE(ALuint, aluF2UI)
1006 DECL_TEMPLATE(ALint, aluF2I)
1007 DECL_TEMPLATE(ALushort, aluF2US)
1008 DECL_TEMPLATE(ALshort, aluF2S)
1009 DECL_TEMPLATE(ALubyte, aluF2UB)
1010 DECL_TEMPLATE(ALbyte, aluF2B)
1012 #undef DECL_TEMPLATE
1015 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1017 ALuint SamplesToDo;
1018 ALeffectslot **slot, **slot_end;
1019 ALsource **src, **src_end;
1020 ALCcontext *ctx;
1021 FPUCtl oldMode;
1022 ALuint i, c;
1024 SetMixerFPUMode(&oldMode);
1026 while(size > 0)
1028 SamplesToDo = minu(size, BUFFERSIZE);
1029 for(c = 0;c < MaxChannels;c++)
1030 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1032 ALCdevice_Lock(device);
1033 V(device->Synth,process)(SamplesToDo, device->DryBuffer);
1035 ctx = device->ContextList;
1036 while(ctx)
1038 ALenum DeferUpdates = ctx->DeferUpdates;
1039 ALenum UpdateSources = AL_FALSE;
1041 if(!DeferUpdates)
1042 UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE);
1044 if(UpdateSources)
1045 CalcListenerParams(ctx->Listener);
1047 /* source processing */
1048 src = ctx->ActiveSources;
1049 src_end = src + ctx->ActiveSourceCount;
1050 while(src != src_end)
1052 if((*src)->state != AL_PLAYING)
1054 --(ctx->ActiveSourceCount);
1055 *src = *(--src_end);
1056 continue;
1059 if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
1060 UpdateSources))
1061 ALsource_Update(*src, ctx);
1063 MixSource(*src, device, SamplesToDo);
1064 src++;
1067 /* effect slot processing */
1068 slot = ctx->ActiveEffectSlots;
1069 slot_end = slot + ctx->ActiveEffectSlotCount;
1070 while(slot != slot_end)
1072 ALfloat offset = (*slot)->ClickRemoval[0];
1073 if(offset < (1.0f/32768.0f))
1074 offset = 0.0f;
1075 else for(i = 0;i < SamplesToDo;i++)
1077 (*slot)->WetBuffer[0][i] += offset;
1078 offset -= offset * (1.0f/256.0f);
1080 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
1081 (*slot)->PendingClicks[0] = 0.0f;
1083 if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
1084 V((*slot)->EffectState,update)(device, *slot);
1086 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1087 device->DryBuffer);
1089 for(i = 0;i < SamplesToDo;i++)
1090 (*slot)->WetBuffer[0][i] = 0.0f;
1092 slot++;
1095 ctx = ctx->next;
1098 slot = &device->DefaultSlot;
1099 if(*slot != NULL)
1101 ALfloat offset = (*slot)->ClickRemoval[0];
1102 if(offset < (1.0f/32768.0f))
1103 offset = 0.0f;
1104 else for(i = 0;i < SamplesToDo;i++)
1106 (*slot)->WetBuffer[0][i] += offset;
1107 offset -= offset * (1.0f/256.0f);
1109 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
1110 (*slot)->PendingClicks[0] = 0.0f;
1112 if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
1113 V((*slot)->EffectState,update)(device, *slot);
1115 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1116 device->DryBuffer);
1118 for(i = 0;i < SamplesToDo;i++)
1119 (*slot)->WetBuffer[0][i] = 0.0f;
1121 ALCdevice_Unlock(device);
1123 /* Click-removal. Could do better; this only really handles immediate
1124 * changes between updates where a predictive sample could be
1125 * generated. Delays caused by effects and HRTF aren't caught. */
1126 if(device->FmtChans == DevFmtMono)
1128 ALfloat offset = device->ClickRemoval[FrontCenter];
1129 if(offset < (1.0f/32768.0f))
1130 offset = 0.0f;
1131 else for(i = 0;i < SamplesToDo;i++)
1133 device->DryBuffer[FrontCenter][i] += offset;
1134 offset -= offset * (1.0f/256.0f);
1136 device->ClickRemoval[FrontCenter] = offset + device->PendingClicks[FrontCenter];
1137 device->PendingClicks[FrontCenter] = 0.0f;
1139 else if(device->FmtChans == DevFmtStereo)
1141 /* Assumes the first two channels are FrontLeft and FrontRight */
1142 for(c = 0;c < 2;c++)
1144 ALfloat offset = device->ClickRemoval[c];
1145 if(offset < (1.0f/32768.0f))
1146 offset = 0.0f;
1147 else for(i = 0;i < SamplesToDo;i++)
1149 device->DryBuffer[c][i] += offset;
1150 offset -= offset * (1.0f/256.0f);
1152 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1153 device->PendingClicks[c] = 0.0f;
1155 if(device->Bs2b)
1157 float samples[2];
1158 for(i = 0;i < SamplesToDo;i++)
1160 samples[0] = device->DryBuffer[FrontLeft][i];
1161 samples[1] = device->DryBuffer[FrontRight][i];
1162 bs2b_cross_feed(device->Bs2b, samples);
1163 device->DryBuffer[FrontLeft][i] = samples[0];
1164 device->DryBuffer[FrontRight][i] = samples[1];
1168 else
1170 for(c = 0;c < MaxChannels;c++)
1172 ALfloat offset = device->ClickRemoval[c];
1173 if(offset < (1.0f/32768.0f))
1174 offset = 0.0f;
1175 else for(i = 0;i < SamplesToDo;i++)
1177 device->DryBuffer[c][i] += offset;
1178 offset -= offset * (1.0f/256.0f);
1180 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1181 device->PendingClicks[c] = 0.0f;
1185 if(buffer)
1187 int bytes = 0;
1188 switch(device->FmtType)
1190 case DevFmtByte:
1191 bytes = Write_ALbyte(device, buffer, SamplesToDo);
1192 break;
1193 case DevFmtUByte:
1194 bytes = Write_ALubyte(device, buffer, SamplesToDo);
1195 break;
1196 case DevFmtShort:
1197 bytes = Write_ALshort(device, buffer, SamplesToDo);
1198 break;
1199 case DevFmtUShort:
1200 bytes = Write_ALushort(device, buffer, SamplesToDo);
1201 break;
1202 case DevFmtInt:
1203 bytes = Write_ALint(device, buffer, SamplesToDo);
1204 break;
1205 case DevFmtUInt:
1206 bytes = Write_ALuint(device, buffer, SamplesToDo);
1207 break;
1208 case DevFmtFloat:
1209 bytes = Write_ALfloat(device, buffer, SamplesToDo);
1210 break;
1213 buffer = (ALubyte*)buffer + bytes;
1216 size -= SamplesToDo;
1219 RestoreFPUMode(&oldMode);
1223 ALvoid aluHandleDisconnect(ALCdevice *device)
1225 ALCcontext *Context;
1227 device->Connected = ALC_FALSE;
1229 Context = device->ContextList;
1230 while(Context)
1232 ALsource **src, **src_end;
1234 src = Context->ActiveSources;
1235 src_end = src + Context->ActiveSourceCount;
1236 while(src != src_end)
1238 if((*src)->state == AL_PLAYING)
1240 (*src)->state = AL_STOPPED;
1241 (*src)->BuffersPlayed = (*src)->BuffersInQueue;
1242 (*src)->position = 0;
1243 (*src)->position_fraction = 0;
1245 src++;
1247 Context->ActiveSourceCount = 0;
1249 Context = Context->next;