Cleanup some ok() macros
[openal-soft.git] / Alc / ALu.c
blobd831e9ca7cce0b0b4eb4179694deff4923e9f074
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"
40 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
42 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
43 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
44 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
47 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
49 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
50 inVector1[2]*inVector2[2];
53 static __inline ALvoid aluNormalize(ALfloat *inVector)
55 ALfloat length, inverse_length;
57 length = aluSqrt(aluDotproduct(inVector, inVector));
58 if(length != 0.0f)
60 inverse_length = 1.0f/length;
61 inVector[0] *= inverse_length;
62 inVector[1] *= inverse_length;
63 inVector[2] *= inverse_length;
67 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
69 ALfloat temp[4] = {
70 vector[0], vector[1], vector[2], w
73 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
74 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
75 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
79 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
81 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
82 ALbufferlistitem *BufferListItem;
83 enum DevFmtChannels DevChans;
84 enum FmtChannels Channels;
85 ALfloat DryGain, DryGainHF;
86 ALfloat WetGain[MAX_SENDS];
87 ALfloat WetGainHF[MAX_SENDS];
88 ALint NumSends, Frequency;
89 ALboolean DupStereo;
90 ALfloat Pitch;
91 ALfloat cw;
92 ALint i;
94 /* Get device properties */
95 DevChans = ALContext->Device->FmtChans;
96 DupStereo = ALContext->Device->DuplicateStereo;
97 NumSends = ALContext->Device->NumAuxSends;
98 Frequency = ALContext->Device->Frequency;
100 /* Get listener properties */
101 ListenerGain = ALContext->Listener.Gain;
103 /* Get source properties */
104 SourceVolume = ALSource->flGain;
105 MinVolume = ALSource->flMinGain;
106 MaxVolume = ALSource->flMaxGain;
107 Pitch = ALSource->flPitch;
109 /* Calculate the stepping value */
110 Channels = FmtMono;
111 BufferListItem = ALSource->queue;
112 while(BufferListItem != NULL)
114 ALbuffer *ALBuffer;
115 if((ALBuffer=BufferListItem->buffer) != NULL)
117 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
118 ALBuffer->FmtType);
119 maxstep -= ResamplerPadding[ALSource->Resampler] +
120 ResamplerPrePadding[ALSource->Resampler] + 1;
121 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
123 Pitch = Pitch * ALBuffer->Frequency / Frequency;
124 if(Pitch > (ALfloat)maxstep)
125 ALSource->Params.Step = maxstep<<FRACTIONBITS;
126 else
128 ALSource->Params.Step = Pitch*FRACTIONONE;
129 if(ALSource->Params.Step == 0)
130 ALSource->Params.Step = 1;
133 Channels = ALBuffer->FmtChannels;
134 break;
136 BufferListItem = BufferListItem->next;
139 /* Calculate gains */
140 DryGain = SourceVolume;
141 DryGain = __min(DryGain,MaxVolume);
142 DryGain = __max(DryGain,MinVolume);
143 DryGainHF = 1.0f;
145 switch(ALSource->DirectFilter.type)
147 case AL_FILTER_LOWPASS:
148 DryGain *= ALSource->DirectFilter.Gain;
149 DryGainHF *= ALSource->DirectFilter.GainHF;
150 break;
153 for(i = 0;i < MAXCHANNELS;i++)
155 ALuint i2;
156 for(i2 = 0;i2 < MAXCHANNELS;i2++)
157 ALSource->Params.DryGains[i][i2] = 0.0f;
160 switch(Channels)
162 case FmtMono:
163 ALSource->Params.DryGains[0][FRONT_CENTER] = DryGain * ListenerGain;
164 break;
165 case FmtStereo:
166 if(DupStereo == AL_FALSE)
168 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
169 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
171 else
173 switch(DevChans)
175 case DevFmtMono:
176 case DevFmtStereo:
177 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
178 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
179 break;
181 case DevFmtQuad:
182 case DevFmtX51:
183 DryGain *= aluSqrt(2.0f/4.0f);
184 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
185 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
186 ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
187 ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
188 break;
190 case DevFmtX61:
191 DryGain *= aluSqrt(2.0f/4.0f);
192 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
193 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
194 ALSource->Params.DryGains[0][SIDE_LEFT] = DryGain * ListenerGain;
195 ALSource->Params.DryGains[1][SIDE_RIGHT] = DryGain * ListenerGain;
196 break;
198 case DevFmtX71:
199 DryGain *= aluSqrt(2.0f/6.0f);
200 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
201 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
202 ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
203 ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
204 ALSource->Params.DryGains[0][SIDE_LEFT] = DryGain * ListenerGain;
205 ALSource->Params.DryGains[1][SIDE_RIGHT] = DryGain * ListenerGain;
206 break;
209 break;
211 case FmtRear:
212 ALSource->Params.DryGains[0][BACK_LEFT] = DryGain * ListenerGain;
213 ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
214 break;
216 case FmtQuad:
217 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
218 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
219 ALSource->Params.DryGains[2][BACK_LEFT] = DryGain * ListenerGain;
220 ALSource->Params.DryGains[3][BACK_RIGHT] = DryGain * ListenerGain;
221 break;
223 case FmtX51:
224 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
225 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
226 ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
227 ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
228 ALSource->Params.DryGains[4][BACK_LEFT] = DryGain * ListenerGain;
229 ALSource->Params.DryGains[5][BACK_RIGHT] = DryGain * ListenerGain;
230 break;
232 case FmtX61:
233 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
234 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
235 ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
236 ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
237 ALSource->Params.DryGains[4][BACK_CENTER] = DryGain * ListenerGain;
238 ALSource->Params.DryGains[5][SIDE_LEFT] = DryGain * ListenerGain;
239 ALSource->Params.DryGains[6][SIDE_RIGHT] = DryGain * ListenerGain;
240 break;
242 case FmtX71:
243 ALSource->Params.DryGains[0][FRONT_LEFT] = DryGain * ListenerGain;
244 ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
245 ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
246 ALSource->Params.DryGains[3][LFE] = DryGain * ListenerGain;
247 ALSource->Params.DryGains[4][BACK_LEFT] = DryGain * ListenerGain;
248 ALSource->Params.DryGains[5][BACK_RIGHT] = DryGain * ListenerGain;
249 ALSource->Params.DryGains[6][SIDE_LEFT] = DryGain * ListenerGain;
250 ALSource->Params.DryGains[7][SIDE_RIGHT] = DryGain * ListenerGain;
251 break;
254 for(i = 0;i < NumSends;i++)
256 WetGain[i] = SourceVolume;
257 WetGain[i] = __min(WetGain[i],MaxVolume);
258 WetGain[i] = __max(WetGain[i],MinVolume);
259 WetGainHF[i] = 1.0f;
261 switch(ALSource->Send[i].WetFilter.type)
263 case AL_FILTER_LOWPASS:
264 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
265 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
266 break;
269 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
272 /* Update filter coefficients. Calculations based on the I3DL2
273 * spec. */
274 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
276 /* We use two chained one-pole filters, so we need to take the
277 * square root of the squared gain, which is the same as the base
278 * gain. */
279 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
281 for(i = 0;i < NumSends;i++)
283 /* We use a one-pole filter, so we need to take the squared gain */
284 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
285 ALSource->Params.Send[i].iirFilter.coeff = a;
289 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
291 const ALCdevice *Device = ALContext->Device;
292 ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
293 ALfloat Direction[3],Position[3],SourceToListener[3];
294 ALfloat Velocity[3],ListenerVel[3];
295 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
296 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
297 ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
298 ALfloat AirAbsorptionFactor;
299 ALbufferlistitem *BufferListItem;
300 ALfloat Attenuation, EffectiveDist;
301 ALfloat RoomAttenuation[MAX_SENDS];
302 ALfloat MetersPerUnit;
303 ALfloat RoomRolloff[MAX_SENDS];
304 ALfloat DryGain;
305 ALfloat DryGainHF;
306 ALfloat WetGain[MAX_SENDS];
307 ALfloat WetGainHF[MAX_SENDS];
308 ALfloat DirGain, AmbientGain;
309 const ALfloat *SpeakerGain;
310 ALfloat Pitch;
311 ALfloat length;
312 ALuint Frequency;
313 ALint NumSends;
314 ALint pos, s, i;
315 ALfloat cw;
317 DryGainHF = 1.0f;
318 for(i = 0;i < MAX_SENDS;i++)
319 WetGainHF[i] = 1.0f;
321 //Get context properties
322 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
323 DopplerVelocity = ALContext->DopplerVelocity;
324 SpeedOfSound = ALContext->flSpeedOfSound;
325 NumSends = Device->NumAuxSends;
326 Frequency = Device->Frequency;
328 //Get listener properties
329 ListenerGain = ALContext->Listener.Gain;
330 MetersPerUnit = ALContext->Listener.MetersPerUnit;
331 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
333 //Get source properties
334 SourceVolume = ALSource->flGain;
335 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
336 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
337 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
338 MinVolume = ALSource->flMinGain;
339 MaxVolume = ALSource->flMaxGain;
340 MinDist = ALSource->flRefDistance;
341 MaxDist = ALSource->flMaxDistance;
342 Rolloff = ALSource->flRollOffFactor;
343 InnerAngle = ALSource->flInnerAngle;
344 OuterAngle = ALSource->flOuterAngle;
345 OuterGainHF = ALSource->OuterGainHF;
346 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
348 //1. Translate Listener to origin (convert to head relative)
349 if(ALSource->bHeadRelative == AL_FALSE)
351 ALfloat U[3],V[3],N[3];
352 ALfloat Matrix[4][4];
354 // Build transform matrix
355 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
356 aluNormalize(N); // Normalized At-vector
357 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
358 aluNormalize(V); // Normalized Up-vector
359 aluCrossproduct(N, V, U); // Right-vector
360 aluNormalize(U); // Normalized Right-vector
361 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
362 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
363 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
364 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
366 // Translate position
367 Position[0] -= ALContext->Listener.Position[0];
368 Position[1] -= ALContext->Listener.Position[1];
369 Position[2] -= ALContext->Listener.Position[2];
371 // Transform source position and direction into listener space
372 aluMatrixVector(Position, 1.0f, Matrix);
373 aluMatrixVector(Direction, 0.0f, Matrix);
374 // Transform source and listener velocity into listener space
375 aluMatrixVector(Velocity, 0.0f, Matrix);
376 aluMatrixVector(ListenerVel, 0.0f, Matrix);
378 else
379 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
381 SourceToListener[0] = -Position[0];
382 SourceToListener[1] = -Position[1];
383 SourceToListener[2] = -Position[2];
384 aluNormalize(SourceToListener);
385 aluNormalize(Direction);
387 //2. Calculate distance attenuation
388 Distance = aluSqrt(aluDotproduct(Position, Position));
389 OrigDist = Distance;
391 Attenuation = 1.0f;
392 for(i = 0;i < NumSends;i++)
394 RoomAttenuation[i] = 1.0f;
396 RoomRolloff[i] = ALSource->RoomRolloffFactor;
397 if(ALSource->Send[i].Slot &&
398 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
399 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
400 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
403 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
404 ALContext->DistanceModel)
406 case AL_INVERSE_DISTANCE_CLAMPED:
407 Distance=__max(Distance,MinDist);
408 Distance=__min(Distance,MaxDist);
409 if(MaxDist < MinDist)
410 break;
411 //fall-through
412 case AL_INVERSE_DISTANCE:
413 if(MinDist > 0.0f)
415 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
416 Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
417 for(i = 0;i < NumSends;i++)
419 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
420 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
423 break;
425 case AL_LINEAR_DISTANCE_CLAMPED:
426 Distance=__max(Distance,MinDist);
427 Distance=__min(Distance,MaxDist);
428 if(MaxDist < MinDist)
429 break;
430 //fall-through
431 case AL_LINEAR_DISTANCE:
432 if(MaxDist != MinDist)
434 Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
435 Attenuation = __max(Attenuation, 0.0f);
436 for(i = 0;i < NumSends;i++)
438 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
439 RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
442 break;
444 case AL_EXPONENT_DISTANCE_CLAMPED:
445 Distance=__max(Distance,MinDist);
446 Distance=__min(Distance,MaxDist);
447 if(MaxDist < MinDist)
448 break;
449 //fall-through
450 case AL_EXPONENT_DISTANCE:
451 if(Distance > 0.0f && MinDist > 0.0f)
453 Attenuation = aluPow(Distance/MinDist, -Rolloff);
454 for(i = 0;i < NumSends;i++)
455 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
457 break;
459 case AL_NONE:
460 break;
463 // Source Gain + Attenuation
464 DryGain = SourceVolume * Attenuation;
465 for(i = 0;i < NumSends;i++)
466 WetGain[i] = SourceVolume * RoomAttenuation[i];
468 EffectiveDist = 0.0f;
469 if(MinDist > 0.0f && Attenuation < 1.0f)
470 EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
472 // Distance-based air absorption
473 if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
475 ALfloat absorb;
477 // Absorption calculation is done in dB
478 absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
479 EffectiveDist;
480 // Convert dB to linear gain before applying
481 absorb = aluPow(10.0f, absorb/20.0f);
483 DryGainHF *= absorb;
486 //3. Apply directional soundcones
487 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
488 if(Angle >= InnerAngle && Angle <= OuterAngle)
490 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
491 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
492 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
494 else if(Angle > OuterAngle)
496 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
497 ConeHF = (1.0f+(OuterGainHF-1.0f));
499 else
501 ConeVolume = 1.0f;
502 ConeHF = 1.0f;
505 // Apply some high-frequency attenuation for sources behind the listener
506 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
507 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
508 // the same as SourceToListener[2]
509 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
510 // Sources within the minimum distance attenuate less
511 if(OrigDist < MinDist)
512 Angle *= OrigDist/MinDist;
513 if(Angle > 90.0f)
515 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
516 ConeHF *= 1.0f - (Device->HeadDampen*scale);
519 DryGain *= ConeVolume;
520 if(ALSource->DryGainHFAuto)
521 DryGainHF *= ConeHF;
523 // Clamp to Min/Max Gain
524 DryGain = __min(DryGain,MaxVolume);
525 DryGain = __max(DryGain,MinVolume);
527 for(i = 0;i < NumSends;i++)
529 ALeffectslot *Slot = ALSource->Send[i].Slot;
531 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
533 ALSource->Params.Send[i].WetGain = 0.0f;
534 WetGainHF[i] = 1.0f;
535 continue;
538 if(Slot->AuxSendAuto)
540 if(ALSource->WetGainAuto)
541 WetGain[i] *= ConeVolume;
542 if(ALSource->WetGainHFAuto)
543 WetGainHF[i] *= ConeHF;
545 // Clamp to Min/Max Gain
546 WetGain[i] = __min(WetGain[i],MaxVolume);
547 WetGain[i] = __max(WetGain[i],MinVolume);
549 if(Slot->effect.type == AL_EFFECT_REVERB ||
550 Slot->effect.type == AL_EFFECT_EAXREVERB)
552 /* Apply a decay-time transformation to the wet path, based on
553 * the attenuation of the dry path.
555 * Using the approximate (effective) source to listener
556 * distance, the initial decay of the reverb effect is
557 * calculated and applied to the wet path.
559 WetGain[i] *= aluPow(10.0f, EffectiveDist /
560 (SPEEDOFSOUNDMETRESPERSEC *
561 Slot->effect.Reverb.DecayTime) *
562 -60.0 / 20.0);
564 WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
565 AirAbsorptionFactor * EffectiveDist);
568 else
570 /* If the slot's auxiliary send auto is off, the data sent to the
571 * effect slot is the same as the dry path, sans filter effects */
572 WetGain[i] = DryGain;
573 WetGainHF[i] = DryGainHF;
576 switch(ALSource->Send[i].WetFilter.type)
578 case AL_FILTER_LOWPASS:
579 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
580 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
581 break;
583 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
586 // Apply filter gains and filters
587 switch(ALSource->DirectFilter.type)
589 case AL_FILTER_LOWPASS:
590 DryGain *= ALSource->DirectFilter.Gain;
591 DryGainHF *= ALSource->DirectFilter.GainHF;
592 break;
594 DryGain *= ListenerGain;
596 // Calculate Velocity
597 Pitch = ALSource->flPitch;
598 if(DopplerFactor != 0.0f)
600 ALfloat VSS, VLS;
601 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
602 DopplerFactor;
604 VSS = aluDotproduct(Velocity, SourceToListener);
605 if(VSS >= MaxVelocity)
606 VSS = (MaxVelocity - 1.0f);
607 else if(VSS <= -MaxVelocity)
608 VSS = -MaxVelocity + 1.0f;
610 VLS = aluDotproduct(ListenerVel, SourceToListener);
611 if(VLS >= MaxVelocity)
612 VLS = (MaxVelocity - 1.0f);
613 else if(VLS <= -MaxVelocity)
614 VLS = -MaxVelocity + 1.0f;
616 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
617 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
620 BufferListItem = ALSource->queue;
621 while(BufferListItem != NULL)
623 ALbuffer *ALBuffer;
624 if((ALBuffer=BufferListItem->buffer) != NULL)
626 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
627 ALBuffer->FmtType);
628 maxstep -= ResamplerPadding[ALSource->Resampler] +
629 ResamplerPrePadding[ALSource->Resampler] + 1;
630 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
632 Pitch = Pitch * ALBuffer->Frequency / Frequency;
633 if(Pitch > (ALfloat)maxstep)
634 ALSource->Params.Step = maxstep<<FRACTIONBITS;
635 else
637 ALSource->Params.Step = Pitch*FRACTIONONE;
638 if(ALSource->Params.Step == 0)
639 ALSource->Params.Step = 1;
641 break;
643 BufferListItem = BufferListItem->next;
646 // Use energy-preserving panning algorithm for multi-speaker playback
647 length = __max(OrigDist, MinDist);
648 if(length > 0.0f)
650 ALfloat invlen = 1.0f/length;
651 Position[0] *= invlen;
652 Position[1] *= invlen;
653 Position[2] *= invlen;
656 pos = aluCart2LUTpos(-Position[2], Position[0]);
657 SpeakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
659 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
660 // elevation adjustment for directional gain. this sucks, but
661 // has low complexity
662 AmbientGain = aluSqrt(1.0/Device->NumChan);
663 for(s = 0;s < MAXCHANNELS;s++)
665 ALuint s2;
666 for(s2 = 0;s2 < MAXCHANNELS;s2++)
667 ALSource->Params.DryGains[s][s2] = 0.0f;
669 for(s = 0;s < (ALsizei)Device->NumChan;s++)
671 Channel chan = Device->Speaker2Chan[s];
672 ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
673 ALSource->Params.DryGains[0][chan] = DryGain * gain;
676 /* Update filter coefficients. */
677 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
679 /* Spatialized sources use four chained one-pole filters, so we need to
680 * take the fourth root of the squared gain, which is the same as the
681 * square root of the base gain. */
682 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
684 for(i = 0;i < NumSends;i++)
686 /* The wet path uses two chained one-pole filters, so take the
687 * base gain (square root of the squared gain) */
688 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
693 static __inline ALfloat aluF2F(ALfloat val)
695 return val;
697 static __inline ALushort aluF2US(ALfloat val)
699 if(val > 1.0f) return 65535;
700 if(val < -1.0f) return 0;
701 return (ALint)(val*32767.0f) + 32768;
703 static __inline ALshort aluF2S(ALfloat val)
705 if(val > 1.0f) return 32767;
706 if(val < -1.0f) return -32768;
707 return (ALint)(val*32767.0f);
709 static __inline ALubyte aluF2UB(ALfloat val)
711 ALushort i = aluF2US(val);
712 return i>>8;
714 static __inline ALbyte aluF2B(ALfloat val)
716 ALshort i = aluF2S(val);
717 return i>>8;
720 static const Channel MonoChans[] = { FRONT_CENTER };
721 static const Channel StereoChans[] = { FRONT_LEFT, FRONT_RIGHT };
722 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
723 BACK_LEFT, BACK_RIGHT };
724 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
725 FRONT_CENTER, LFE,
726 BACK_LEFT, BACK_RIGHT };
727 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_LEFT,
728 FRONT_CENTER, LFE, BACK_CENTER,
729 SIDE_LEFT, SIDE_RIGHT };
730 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
731 FRONT_CENTER, LFE,
732 BACK_LEFT, BACK_RIGHT,
733 SIDE_LEFT, SIDE_RIGHT };
735 #define DECL_TEMPLATE(T, chans,N, func) \
736 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
738 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
739 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
740 const ALuint *ChanMap = device->DevChannels; \
741 ALuint i, j, c; \
743 for(i = 0;i < SamplesToDo;i++) \
745 for(j = 0;j < N;j++) \
747 ALfloat samp = 0.0f; \
748 for(c = 0;c < MAXCHANNELS;c++) \
749 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
750 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
752 buffer = ((T*)buffer) + N; \
756 DECL_TEMPLATE(ALfloat, MonoChans,1, aluF2F)
757 DECL_TEMPLATE(ALfloat, QuadChans,4, aluF2F)
758 DECL_TEMPLATE(ALfloat, X51Chans,6, aluF2F)
759 DECL_TEMPLATE(ALfloat, X61Chans,7, aluF2F)
760 DECL_TEMPLATE(ALfloat, X71Chans,8, aluF2F)
762 DECL_TEMPLATE(ALushort, MonoChans,1, aluF2US)
763 DECL_TEMPLATE(ALushort, QuadChans,4, aluF2US)
764 DECL_TEMPLATE(ALushort, X51Chans,6, aluF2US)
765 DECL_TEMPLATE(ALushort, X61Chans,7, aluF2US)
766 DECL_TEMPLATE(ALushort, X71Chans,8, aluF2US)
768 DECL_TEMPLATE(ALshort, MonoChans,1, aluF2S)
769 DECL_TEMPLATE(ALshort, QuadChans,4, aluF2S)
770 DECL_TEMPLATE(ALshort, X51Chans,6, aluF2S)
771 DECL_TEMPLATE(ALshort, X61Chans,7, aluF2S)
772 DECL_TEMPLATE(ALshort, X71Chans,8, aluF2S)
774 DECL_TEMPLATE(ALubyte, MonoChans,1, aluF2UB)
775 DECL_TEMPLATE(ALubyte, QuadChans,4, aluF2UB)
776 DECL_TEMPLATE(ALubyte, X51Chans,6, aluF2UB)
777 DECL_TEMPLATE(ALubyte, X61Chans,7, aluF2UB)
778 DECL_TEMPLATE(ALubyte, X71Chans,8, aluF2UB)
780 DECL_TEMPLATE(ALbyte, MonoChans,1, aluF2B)
781 DECL_TEMPLATE(ALbyte, QuadChans,4, aluF2B)
782 DECL_TEMPLATE(ALbyte, X51Chans,6, aluF2B)
783 DECL_TEMPLATE(ALbyte, X61Chans,7, aluF2B)
784 DECL_TEMPLATE(ALbyte, X71Chans,8, aluF2B)
786 #undef DECL_TEMPLATE
788 #define DECL_TEMPLATE(T, chans,N, func) \
789 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
791 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
792 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
793 const ALuint *ChanMap = device->DevChannels; \
794 ALuint i, j, c; \
796 if(device->Bs2b) \
798 for(i = 0;i < SamplesToDo;i++) \
800 float samples[2] = { 0.0f, 0.0f }; \
801 for(c = 0;c < MAXCHANNELS;c++) \
803 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
804 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
806 bs2b_cross_feed(device->Bs2b, samples); \
807 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
808 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
809 buffer = ((T*)buffer) + 2; \
812 else \
814 for(i = 0;i < SamplesToDo;i++) \
816 for(j = 0;j < N;j++) \
818 ALfloat samp = 0.0f; \
819 for(c = 0;c < MAXCHANNELS;c++) \
820 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
821 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
823 buffer = ((T*)buffer) + N; \
828 DECL_TEMPLATE(ALfloat, StereoChans,2, aluF2F)
829 DECL_TEMPLATE(ALushort, StereoChans,2, aluF2US)
830 DECL_TEMPLATE(ALshort, StereoChans,2, aluF2S)
831 DECL_TEMPLATE(ALubyte, StereoChans,2, aluF2UB)
832 DECL_TEMPLATE(ALbyte, StereoChans,2, aluF2B)
834 #undef DECL_TEMPLATE
836 #define DECL_TEMPLATE(T, func) \
837 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
839 switch(device->FmtChans) \
841 case DevFmtMono: \
842 Write_##T##_MonoChans(device, buffer, SamplesToDo); \
843 break; \
844 case DevFmtStereo: \
845 Write_##T##_StereoChans(device, buffer, SamplesToDo); \
846 break; \
847 case DevFmtQuad: \
848 Write_##T##_QuadChans(device, buffer, SamplesToDo); \
849 break; \
850 case DevFmtX51: \
851 Write_##T##_X51Chans(device, buffer, SamplesToDo); \
852 break; \
853 case DevFmtX61: \
854 Write_##T##_X61Chans(device, buffer, SamplesToDo); \
855 break; \
856 case DevFmtX71: \
857 Write_##T##_X71Chans(device, buffer, SamplesToDo); \
858 break; \
862 DECL_TEMPLATE(ALfloat, aluF2F)
863 DECL_TEMPLATE(ALushort, aluF2US)
864 DECL_TEMPLATE(ALshort, aluF2S)
865 DECL_TEMPLATE(ALubyte, aluF2UB)
866 DECL_TEMPLATE(ALbyte, aluF2B)
868 #undef DECL_TEMPLATE
870 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
872 ALuint SamplesToDo;
873 ALeffectslot *ALEffectSlot;
874 ALCcontext **ctx, **ctx_end;
875 ALsource **src, **src_end;
876 int fpuState;
877 ALuint i, c;
878 ALsizei e;
880 #if defined(HAVE_FESETROUND)
881 fpuState = fegetround();
882 fesetround(FE_TOWARDZERO);
883 #elif defined(HAVE__CONTROLFP)
884 fpuState = _controlfp(_RC_CHOP, _MCW_RC);
885 #else
886 (void)fpuState;
887 #endif
889 while(size > 0)
891 /* Setup variables */
892 SamplesToDo = min(size, BUFFERSIZE);
894 /* Clear mixing buffer */
895 memset(device->DryBuffer, 0, SamplesToDo*MAXCHANNELS*sizeof(ALfloat));
897 SuspendContext(NULL);
898 ctx = device->Contexts;
899 ctx_end = ctx + device->NumContexts;
900 while(ctx != ctx_end)
902 SuspendContext(*ctx);
904 src = (*ctx)->ActiveSources;
905 src_end = src + (*ctx)->ActiveSourceCount;
906 while(src != src_end)
908 if((*src)->state != AL_PLAYING)
910 --((*ctx)->ActiveSourceCount);
911 *src = *(--src_end);
912 continue;
915 if((*src)->NeedsUpdate)
917 ALsource_Update(*src, *ctx);
918 (*src)->NeedsUpdate = AL_FALSE;
921 MixSource(*src, device, SamplesToDo);
922 src++;
925 /* effect slot processing */
926 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
928 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
930 for(i = 0;i < SamplesToDo;i++)
932 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
933 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
935 for(i = 0;i < 1;i++)
937 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
938 ALEffectSlot->PendingClicks[i] = 0.0f;
941 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
942 SamplesToDo, ALEffectSlot->WetBuffer,
943 device->DryBuffer);
945 for(i = 0;i < SamplesToDo;i++)
946 ALEffectSlot->WetBuffer[i] = 0.0f;
949 ProcessContext(*ctx);
950 ctx++;
952 ProcessContext(NULL);
954 //Post processing loop
955 for(i = 0;i < SamplesToDo;i++)
957 for(c = 0;c < MAXCHANNELS;c++)
959 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
960 device->DryBuffer[i][c] += device->ClickRemoval[c];
963 for(i = 0;i < MAXCHANNELS;i++)
965 device->ClickRemoval[i] += device->PendingClicks[i];
966 device->PendingClicks[i] = 0.0f;
969 switch(device->FmtType)
971 case DevFmtByte:
972 Write_ALbyte(device, buffer, SamplesToDo);
973 break;
974 case DevFmtUByte:
975 Write_ALubyte(device, buffer, SamplesToDo);
976 break;
977 case DevFmtShort:
978 Write_ALshort(device, buffer, SamplesToDo);
979 break;
980 case DevFmtUShort:
981 Write_ALushort(device, buffer, SamplesToDo);
982 break;
983 case DevFmtFloat:
984 Write_ALfloat(device, buffer, SamplesToDo);
985 break;
988 size -= SamplesToDo;
991 #if defined(HAVE_FESETROUND)
992 fesetround(fpuState);
993 #elif defined(HAVE__CONTROLFP)
994 _controlfp(fpuState, _MCW_RC);
995 #endif
999 ALvoid aluHandleDisconnect(ALCdevice *device)
1001 ALuint i;
1003 SuspendContext(NULL);
1004 for(i = 0;i < device->NumContexts;i++)
1006 ALCcontext *Context = device->Contexts[i];
1007 ALsource *source;
1008 ALsizei pos;
1010 SuspendContext(Context);
1012 for(pos = 0;pos < Context->SourceMap.size;pos++)
1014 source = Context->SourceMap.array[pos].value;
1015 if(source->state == AL_PLAYING)
1017 source->state = AL_STOPPED;
1018 source->BuffersPlayed = source->BuffersInQueue;
1019 source->position = 0;
1020 source->position_fraction = 0;
1023 ProcessContext(Context);
1026 device->Connected = ALC_FALSE;
1027 ProcessContext(NULL);