Store air absorption factor locally
[openal-soft.git] / Alc / ALu.c
blobd54b9f09016118e58ea74c91d95bcef54fc4e986
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 ALfloat DryGain, DryGainHF;
84 ALfloat WetGain[MAX_SENDS];
85 ALfloat WetGainHF[MAX_SENDS];
86 ALint NumSends, Frequency;
87 ALboolean DupStereo;
88 ALint Channels;
89 ALfloat Pitch;
90 ALenum Format;
91 ALfloat cw;
92 ALint i;
94 //Get context properties
95 Format = ALContext->Device->Format;
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;
108 //1. Multi-channel buffers always play "normal"
109 Channels = 0;
110 Pitch = ALSource->flPitch;
111 BufferListItem = ALSource->queue;
112 while(BufferListItem != NULL)
114 ALbuffer *ALBuffer;
115 if((ALBuffer=BufferListItem->buffer) != NULL)
117 Channels = aluChannelsFromFormat(ALBuffer->format);
118 Pitch = Pitch * ALBuffer->frequency / Frequency;
119 break;
121 BufferListItem = BufferListItem->next;
124 if(Pitch > (float)MAX_PITCH)
125 ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS;
126 else if(!(Pitch > 0.0f))
127 ALSource->Params.Step = 1<<FRACTIONBITS;
128 else
130 ALSource->Params.Step = Pitch*(1<<FRACTIONBITS);
131 if(ALSource->Params.Step == 0)
132 ALSource->Params.Step = 1;
135 DryGain = SourceVolume;
136 DryGain = __min(DryGain,MaxVolume);
137 DryGain = __max(DryGain,MinVolume);
138 DryGainHF = 1.0f;
140 switch(ALSource->DirectFilter.type)
142 case AL_FILTER_LOWPASS:
143 DryGain *= ALSource->DirectFilter.Gain;
144 DryGainHF *= ALSource->DirectFilter.GainHF;
145 break;
148 if(Channels == 2)
150 for(i = 0;i < OUTPUTCHANNELS;i++)
151 ALSource->Params.DryGains[i] = 0.0f;
153 if(DupStereo == AL_FALSE)
155 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
156 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
158 else
160 switch(Format)
162 case AL_FORMAT_MONO8:
163 case AL_FORMAT_MONO16:
164 case AL_FORMAT_MONO_FLOAT32:
165 case AL_FORMAT_STEREO8:
166 case AL_FORMAT_STEREO16:
167 case AL_FORMAT_STEREO_FLOAT32:
168 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
169 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
170 break;
172 case AL_FORMAT_QUAD8:
173 case AL_FORMAT_QUAD16:
174 case AL_FORMAT_QUAD32:
175 case AL_FORMAT_51CHN8:
176 case AL_FORMAT_51CHN16:
177 case AL_FORMAT_51CHN32:
178 DryGain *= aluSqrt(2.0f/4.0f);
179 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
180 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
181 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
182 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
183 break;
185 case AL_FORMAT_61CHN8:
186 case AL_FORMAT_61CHN16:
187 case AL_FORMAT_61CHN32:
188 DryGain *= aluSqrt(2.0f/4.0f);
189 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
190 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
191 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
192 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
193 break;
195 case AL_FORMAT_71CHN8:
196 case AL_FORMAT_71CHN16:
197 case AL_FORMAT_71CHN32:
198 DryGain *= aluSqrt(2.0f/6.0f);
199 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
200 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
201 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
202 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
203 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
204 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
205 break;
207 default:
208 break;
212 else
214 for(i = 0;i < OUTPUTCHANNELS;i++)
215 ALSource->Params.DryGains[i] = DryGain * ListenerGain;
218 for(i = 0;i < NumSends;i++)
220 WetGain[i] = SourceVolume;
221 WetGain[i] = __min(WetGain[i],MaxVolume);
222 WetGain[i] = __max(WetGain[i],MinVolume);
223 WetGainHF[i] = 1.0f;
225 switch(ALSource->Send[i].WetFilter.type)
227 case AL_FILTER_LOWPASS:
228 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
229 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
230 break;
233 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
235 for(i = NumSends;i < MAX_SENDS;i++)
237 ALSource->Params.WetGains[i] = 0.0f;
238 WetGainHF[i] = 1.0f;
241 /* Update filter coefficients. Calculations based on the I3DL2
242 * spec. */
243 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
245 /* We use two chained one-pole filters, so we need to take the
246 * square root of the squared gain, which is the same as the base
247 * gain. */
248 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
250 for(i = 0;i < NumSends;i++)
252 /* We use a one-pole filter, so we need to take the squared gain */
253 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
254 ALSource->Params.Send[i].iirFilter.coeff = a;
258 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
260 const ALCdevice *Device = ALContext->Device;
261 ALfloat InnerAngle,OuterAngle,Angle,Distance,DryMix,OrigDist;
262 ALfloat Direction[3],Position[3],SourceToListener[3];
263 ALfloat Velocity[3],ListenerVel[3];
264 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
265 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
266 ALfloat DopplerFactor, DopplerVelocity, flSpeedOfSound;
267 ALfloat AirAbsorptionFactor;
268 ALbufferlistitem *BufferListItem;
269 ALfloat Matrix[4][4];
270 ALfloat flAttenuation, effectiveDist;
271 ALfloat RoomAttenuation[MAX_SENDS];
272 ALfloat MetersPerUnit;
273 ALfloat RoomRolloff[MAX_SENDS];
274 ALfloat DryGainHF = 1.0f;
275 ALfloat WetGain[MAX_SENDS];
276 ALfloat WetGainHF[MAX_SENDS];
277 ALfloat DirGain, AmbientGain;
278 const ALfloat *SpeakerGain;
279 ALfloat Pitch;
280 ALfloat length;
281 ALuint Frequency;
282 ALint NumSends;
283 ALint pos, s, i;
284 ALfloat cw;
286 for(i = 0;i < MAX_SENDS;i++)
287 WetGainHF[i] = 1.0f;
289 //Get context properties
290 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
291 DopplerVelocity = ALContext->DopplerVelocity;
292 flSpeedOfSound = ALContext->flSpeedOfSound;
293 NumSends = Device->NumAuxSends;
294 Frequency = Device->Frequency;
296 //Get listener properties
297 ListenerGain = ALContext->Listener.Gain;
298 MetersPerUnit = ALContext->Listener.MetersPerUnit;
299 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
301 //Get source properties
302 SourceVolume = ALSource->flGain;
303 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
304 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
305 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
306 MinVolume = ALSource->flMinGain;
307 MaxVolume = ALSource->flMaxGain;
308 MinDist = ALSource->flRefDistance;
309 MaxDist = ALSource->flMaxDistance;
310 Rolloff = ALSource->flRollOffFactor;
311 InnerAngle = ALSource->flInnerAngle;
312 OuterAngle = ALSource->flOuterAngle;
313 OuterGainHF = ALSource->OuterGainHF;
314 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
316 //1. Translate Listener to origin (convert to head relative)
317 if(ALSource->bHeadRelative==AL_FALSE)
319 ALfloat U[3],V[3],N[3];
321 // Build transform matrix
322 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
323 aluNormalize(N); // Normalized At-vector
324 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
325 aluNormalize(V); // Normalized Up-vector
326 aluCrossproduct(N, V, U); // Right-vector
327 aluNormalize(U); // Normalized Right-vector
328 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
329 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
330 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
331 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
333 // Translate position
334 Position[0] -= ALContext->Listener.Position[0];
335 Position[1] -= ALContext->Listener.Position[1];
336 Position[2] -= ALContext->Listener.Position[2];
338 // Transform source position and direction into listener space
339 aluMatrixVector(Position, 1.0f, Matrix);
340 aluMatrixVector(Direction, 0.0f, Matrix);
341 // Transform source and listener velocity into listener space
342 aluMatrixVector(Velocity, 0.0f, Matrix);
343 aluMatrixVector(ListenerVel, 0.0f, Matrix);
345 else
346 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
348 SourceToListener[0] = -Position[0];
349 SourceToListener[1] = -Position[1];
350 SourceToListener[2] = -Position[2];
351 aluNormalize(SourceToListener);
352 aluNormalize(Direction);
354 //2. Calculate distance attenuation
355 Distance = aluSqrt(aluDotproduct(Position, Position));
356 OrigDist = Distance;
358 flAttenuation = 1.0f;
359 for(i = 0;i < NumSends;i++)
361 RoomAttenuation[i] = 1.0f;
363 RoomRolloff[i] = ALSource->RoomRolloffFactor;
364 if(ALSource->Send[i].Slot &&
365 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
366 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
367 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
370 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
371 ALContext->DistanceModel)
373 case AL_INVERSE_DISTANCE_CLAMPED:
374 Distance=__max(Distance,MinDist);
375 Distance=__min(Distance,MaxDist);
376 if(MaxDist < MinDist)
377 break;
378 //fall-through
379 case AL_INVERSE_DISTANCE:
380 if(MinDist > 0.0f)
382 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
383 flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
384 for(i = 0;i < NumSends;i++)
386 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
387 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
390 break;
392 case AL_LINEAR_DISTANCE_CLAMPED:
393 Distance=__max(Distance,MinDist);
394 Distance=__min(Distance,MaxDist);
395 if(MaxDist < MinDist)
396 break;
397 //fall-through
398 case AL_LINEAR_DISTANCE:
399 Distance=__min(Distance,MaxDist);
400 if(MaxDist != MinDist)
402 flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
403 for(i = 0;i < NumSends;i++)
404 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
406 break;
408 case AL_EXPONENT_DISTANCE_CLAMPED:
409 Distance=__max(Distance,MinDist);
410 Distance=__min(Distance,MaxDist);
411 if(MaxDist < MinDist)
412 break;
413 //fall-through
414 case AL_EXPONENT_DISTANCE:
415 if(Distance > 0.0f && MinDist > 0.0f)
417 flAttenuation = aluPow(Distance/MinDist, -Rolloff);
418 for(i = 0;i < NumSends;i++)
419 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
421 break;
423 case AL_NONE:
424 break;
427 // Source Gain + Attenuation
428 DryMix = SourceVolume * flAttenuation;
429 for(i = 0;i < NumSends;i++)
430 WetGain[i] = SourceVolume * RoomAttenuation[i];
432 effectiveDist = 0.0f;
433 if(MinDist > 0.0f && flAttenuation < 1.0f)
434 effectiveDist = (MinDist/flAttenuation - MinDist)*MetersPerUnit;
436 // Distance-based air absorption
437 if(AirAbsorptionFactor > 0.0f && effectiveDist > 0.0f)
439 ALfloat absorb;
441 // Absorption calculation is done in dB
442 absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
443 effectiveDist;
444 // Convert dB to linear gain before applying
445 absorb = aluPow(10.0f, absorb/20.0f);
447 DryGainHF *= absorb;
450 //3. Apply directional soundcones
451 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
452 if(Angle >= InnerAngle && Angle <= OuterAngle)
454 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
455 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
456 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
458 else if(Angle > OuterAngle)
460 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
461 ConeHF = (1.0f+(OuterGainHF-1.0f));
463 else
465 ConeVolume = 1.0f;
466 ConeHF = 1.0f;
469 // Apply some high-frequency attenuation for sources behind the listener
470 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
471 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
472 // the same as SourceToListener[2]
473 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
474 // Sources within the minimum distance attenuate less
475 if(OrigDist < MinDist)
476 Angle *= OrigDist/MinDist;
477 if(Angle > 90.0f)
479 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
480 ConeHF *= 1.0f - (Device->HeadDampen*scale);
483 DryMix *= ConeVolume;
484 if(ALSource->DryGainHFAuto)
485 DryGainHF *= ConeHF;
487 // Clamp to Min/Max Gain
488 DryMix = __min(DryMix,MaxVolume);
489 DryMix = __max(DryMix,MinVolume);
491 for(i = 0;i < NumSends;i++)
493 ALeffectslot *Slot = ALSource->Send[i].Slot;
495 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
497 ALSource->Params.WetGains[i] = 0.0f;
498 WetGainHF[i] = 1.0f;
499 continue;
502 if(Slot->AuxSendAuto)
504 if(ALSource->WetGainAuto)
505 WetGain[i] *= ConeVolume;
506 if(ALSource->WetGainHFAuto)
507 WetGainHF[i] *= ConeHF;
509 // Clamp to Min/Max Gain
510 WetGain[i] = __min(WetGain[i],MaxVolume);
511 WetGain[i] = __max(WetGain[i],MinVolume);
513 if(Slot->effect.type == AL_EFFECT_REVERB ||
514 Slot->effect.type == AL_EFFECT_EAXREVERB)
516 /* Apply a decay-time transformation to the wet path, based on
517 * the attenuation of the dry path.
519 * Using the approximate (effective) source to listener
520 * distance, the initial decay of the reverb effect is
521 * calculated and applied to the wet path.
523 WetGain[i] *= aluPow(10.0f, effectiveDist /
524 (SPEEDOFSOUNDMETRESPERSEC *
525 Slot->effect.Reverb.DecayTime) *
526 -60.0 / 20.0);
528 WetGainHF[i] *= aluPow(10.0f,
529 log10(Slot->effect.Reverb.AirAbsorptionGainHF) *
530 AirAbsorptionFactor * effectiveDist);
533 else
535 /* If the slot's auxiliary send auto is off, the data sent to the
536 * effect slot is the same as the dry path, sans filter effects */
537 WetGain[i] = DryMix;
538 WetGainHF[i] = DryGainHF;
541 switch(ALSource->Send[i].WetFilter.type)
543 case AL_FILTER_LOWPASS:
544 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
545 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
546 break;
548 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
550 for(i = NumSends;i < MAX_SENDS;i++)
552 ALSource->Params.WetGains[i] = 0.0f;
553 WetGainHF[i] = 1.0f;
556 // Apply filter gains and filters
557 switch(ALSource->DirectFilter.type)
559 case AL_FILTER_LOWPASS:
560 DryMix *= ALSource->DirectFilter.Gain;
561 DryGainHF *= ALSource->DirectFilter.GainHF;
562 break;
564 DryMix *= ListenerGain;
566 // Calculate Velocity
567 if(DopplerFactor != 0.0f)
569 ALfloat flVSS, flVLS;
570 ALfloat flMaxVelocity = (DopplerVelocity * flSpeedOfSound) /
571 DopplerFactor;
573 flVSS = aluDotproduct(Velocity, SourceToListener);
574 if(flVSS >= flMaxVelocity)
575 flVSS = (flMaxVelocity - 1.0f);
576 else if(flVSS <= -flMaxVelocity)
577 flVSS = -flMaxVelocity + 1.0f;
579 flVLS = aluDotproduct(ListenerVel, SourceToListener);
580 if(flVLS >= flMaxVelocity)
581 flVLS = (flMaxVelocity - 1.0f);
582 else if(flVLS <= -flMaxVelocity)
583 flVLS = -flMaxVelocity + 1.0f;
585 Pitch = ALSource->flPitch *
586 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) /
587 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS));
589 else
590 Pitch = ALSource->flPitch;
592 BufferListItem = ALSource->queue;
593 while(BufferListItem != NULL)
595 ALbuffer *ALBuffer;
596 if((ALBuffer=BufferListItem->buffer) != NULL)
598 Pitch = Pitch * ALBuffer->frequency / Frequency;
599 break;
601 BufferListItem = BufferListItem->next;
604 if(Pitch > (float)MAX_PITCH)
605 ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS;
606 else if(!(Pitch > 0.0f))
607 ALSource->Params.Step = 1<<FRACTIONBITS;
608 else
610 ALSource->Params.Step = Pitch*(1<<FRACTIONBITS);
611 if(ALSource->Params.Step == 0)
612 ALSource->Params.Step = 1;
615 // Use energy-preserving panning algorithm for multi-speaker playback
616 length = __max(OrigDist, MinDist);
617 if(length > 0.0f)
619 ALfloat invlen = 1.0f/length;
620 Position[0] *= invlen;
621 Position[1] *= invlen;
622 Position[2] *= invlen;
625 pos = aluCart2LUTpos(-Position[2], Position[0]);
626 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
628 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
629 // elevation adjustment for directional gain. this sucks, but
630 // has low complexity
631 AmbientGain = 1.0/aluSqrt(Device->NumChan) * (1.0-DirGain);
632 for(s = 0;s < OUTPUTCHANNELS;s++)
633 ALSource->Params.DryGains[s] = 0.0f;
634 for(s = 0;s < (ALsizei)Device->NumChan;s++)
636 Channel chan = Device->Speaker2Chan[s];
637 ALfloat gain = SpeakerGain[chan]*DirGain + AmbientGain;
638 ALSource->Params.DryGains[chan] = DryMix * gain;
641 /* Update filter coefficients. */
642 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
644 /* Spatialized sources use four chained one-pole filters, so we need to
645 * take the fourth root of the squared gain, which is the same as the
646 * square root of the base gain. */
647 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
649 for(i = 0;i < NumSends;i++)
651 /* The wet path uses two chained one-pole filters, so take the
652 * base gain (square root of the squared gain) */
653 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
658 ALvoid aluHandleDisconnect(ALCdevice *device)
660 ALuint i;
662 SuspendContext(NULL);
663 for(i = 0;i < device->NumContexts;i++)
665 ALCcontext *Context = device->Contexts[i];
666 ALsource *source;
667 ALsizei pos;
669 SuspendContext(Context);
671 for(pos = 0;pos < Context->SourceMap.size;pos++)
673 source = Context->SourceMap.array[pos].value;
674 if(source->state == AL_PLAYING)
676 source->state = AL_STOPPED;
677 source->BuffersPlayed = source->BuffersInQueue;
678 source->position = 0;
679 source->position_fraction = 0;
682 ProcessContext(Context);
685 device->Connected = ALC_FALSE;
686 ProcessContext(NULL);