Better protect against sample overflow when converting float to short
[openal-soft.git] / Alc / ALu.c
blob0cccf0f02aa7db5c815266f1c9d7c722938c8b96
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 ALbufferlistitem *BufferListItem;
268 ALfloat Matrix[4][4];
269 ALfloat flAttenuation, effectiveDist;
270 ALfloat RoomAttenuation[MAX_SENDS];
271 ALfloat MetersPerUnit;
272 ALfloat RoomRolloff[MAX_SENDS];
273 ALfloat DryGainHF = 1.0f;
274 ALfloat WetGain[MAX_SENDS];
275 ALfloat WetGainHF[MAX_SENDS];
276 ALfloat DirGain, AmbientGain;
277 const ALfloat *SpeakerGain;
278 ALfloat Pitch;
279 ALfloat length;
280 ALuint Frequency;
281 ALint NumSends;
282 ALint pos, s, i;
283 ALfloat cw;
285 for(i = 0;i < MAX_SENDS;i++)
286 WetGainHF[i] = 1.0f;
288 //Get context properties
289 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
290 DopplerVelocity = ALContext->DopplerVelocity;
291 flSpeedOfSound = ALContext->flSpeedOfSound;
292 NumSends = Device->NumAuxSends;
293 Frequency = Device->Frequency;
295 //Get listener properties
296 ListenerGain = ALContext->Listener.Gain;
297 MetersPerUnit = ALContext->Listener.MetersPerUnit;
298 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
300 //Get source properties
301 SourceVolume = ALSource->flGain;
302 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
303 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
304 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
305 MinVolume = ALSource->flMinGain;
306 MaxVolume = ALSource->flMaxGain;
307 MinDist = ALSource->flRefDistance;
308 MaxDist = ALSource->flMaxDistance;
309 Rolloff = ALSource->flRollOffFactor;
310 InnerAngle = ALSource->flInnerAngle;
311 OuterAngle = ALSource->flOuterAngle;
312 OuterGainHF = ALSource->OuterGainHF;
314 //1. Translate Listener to origin (convert to head relative)
315 if(ALSource->bHeadRelative==AL_FALSE)
317 ALfloat U[3],V[3],N[3];
319 // Build transform matrix
320 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
321 aluNormalize(N); // Normalized At-vector
322 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
323 aluNormalize(V); // Normalized Up-vector
324 aluCrossproduct(N, V, U); // Right-vector
325 aluNormalize(U); // Normalized Right-vector
326 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
327 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
328 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
329 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
331 // Translate position
332 Position[0] -= ALContext->Listener.Position[0];
333 Position[1] -= ALContext->Listener.Position[1];
334 Position[2] -= ALContext->Listener.Position[2];
336 // Transform source position and direction into listener space
337 aluMatrixVector(Position, 1.0f, Matrix);
338 aluMatrixVector(Direction, 0.0f, Matrix);
339 // Transform source and listener velocity into listener space
340 aluMatrixVector(Velocity, 0.0f, Matrix);
341 aluMatrixVector(ListenerVel, 0.0f, Matrix);
343 else
344 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
346 SourceToListener[0] = -Position[0];
347 SourceToListener[1] = -Position[1];
348 SourceToListener[2] = -Position[2];
349 aluNormalize(SourceToListener);
350 aluNormalize(Direction);
352 //2. Calculate distance attenuation
353 Distance = aluSqrt(aluDotproduct(Position, Position));
354 OrigDist = Distance;
356 flAttenuation = 1.0f;
357 for(i = 0;i < NumSends;i++)
359 RoomAttenuation[i] = 1.0f;
361 RoomRolloff[i] = ALSource->RoomRolloffFactor;
362 if(ALSource->Send[i].Slot &&
363 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
364 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
365 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
368 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
369 ALContext->DistanceModel)
371 case AL_INVERSE_DISTANCE_CLAMPED:
372 Distance=__max(Distance,MinDist);
373 Distance=__min(Distance,MaxDist);
374 if(MaxDist < MinDist)
375 break;
376 //fall-through
377 case AL_INVERSE_DISTANCE:
378 if(MinDist > 0.0f)
380 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
381 flAttenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
382 for(i = 0;i < NumSends;i++)
384 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
385 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
388 break;
390 case AL_LINEAR_DISTANCE_CLAMPED:
391 Distance=__max(Distance,MinDist);
392 Distance=__min(Distance,MaxDist);
393 if(MaxDist < MinDist)
394 break;
395 //fall-through
396 case AL_LINEAR_DISTANCE:
397 Distance=__min(Distance,MaxDist);
398 if(MaxDist != MinDist)
400 flAttenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
401 for(i = 0;i < NumSends;i++)
402 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
404 break;
406 case AL_EXPONENT_DISTANCE_CLAMPED:
407 Distance=__max(Distance,MinDist);
408 Distance=__min(Distance,MaxDist);
409 if(MaxDist < MinDist)
410 break;
411 //fall-through
412 case AL_EXPONENT_DISTANCE:
413 if(Distance > 0.0f && MinDist > 0.0f)
415 flAttenuation = aluPow(Distance/MinDist, -Rolloff);
416 for(i = 0;i < NumSends;i++)
417 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
419 break;
421 case AL_NONE:
422 break;
425 // Source Gain + Attenuation
426 DryMix = SourceVolume * flAttenuation;
427 for(i = 0;i < NumSends;i++)
428 WetGain[i] = SourceVolume * RoomAttenuation[i];
430 effectiveDist = 0.0f;
431 if(MinDist > 0.0f)
432 effectiveDist = (MinDist/flAttenuation - MinDist)*MetersPerUnit;
434 // Distance-based air absorption
435 if(ALSource->AirAbsorptionFactor > 0.0f && effectiveDist > 0.0f)
437 ALfloat absorb;
439 // Absorption calculation is done in dB
440 absorb = (ALSource->AirAbsorptionFactor*AIRABSORBGAINDBHF) *
441 effectiveDist;
442 // Convert dB to linear gain before applying
443 absorb = aluPow(10.0f, absorb/20.0f);
445 DryGainHF *= absorb;
448 //3. Apply directional soundcones
449 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
450 if(Angle >= InnerAngle && Angle <= OuterAngle)
452 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
453 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
454 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
456 else if(Angle > OuterAngle)
458 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
459 ConeHF = (1.0f+(OuterGainHF-1.0f));
461 else
463 ConeVolume = 1.0f;
464 ConeHF = 1.0f;
467 // Apply some high-frequency attenuation for sources behind the listener
468 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
469 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
470 // the same as SourceToListener[2]
471 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
472 // Sources within the minimum distance attenuate less
473 if(OrigDist < MinDist)
474 Angle *= OrigDist/MinDist;
475 if(Angle > 90.0f)
477 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
478 ConeHF *= 1.0f - (Device->HeadDampen*scale);
481 DryMix *= ConeVolume;
482 if(ALSource->DryGainHFAuto)
483 DryGainHF *= ConeHF;
485 // Clamp to Min/Max Gain
486 DryMix = __min(DryMix,MaxVolume);
487 DryMix = __max(DryMix,MinVolume);
489 for(i = 0;i < NumSends;i++)
491 ALeffectslot *Slot = ALSource->Send[i].Slot;
493 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
495 ALSource->Params.WetGains[i] = 0.0f;
496 WetGainHF[i] = 1.0f;
497 continue;
500 if(Slot->AuxSendAuto)
502 if(ALSource->WetGainAuto)
503 WetGain[i] *= ConeVolume;
504 if(ALSource->WetGainHFAuto)
505 WetGainHF[i] *= ConeHF;
507 // Clamp to Min/Max Gain
508 WetGain[i] = __min(WetGain[i],MaxVolume);
509 WetGain[i] = __max(WetGain[i],MinVolume);
511 if(Slot->effect.type == AL_EFFECT_REVERB ||
512 Slot->effect.type == AL_EFFECT_EAXREVERB)
514 /* Apply a decay-time transformation to the wet path, based on
515 * the attenuation of the dry path.
517 * Using the approximate (effective) source to listener
518 * distance, the initial decay of the reverb effect is
519 * calculated and applied to the wet path.
521 WetGain[i] *= aluPow(10.0f, effectiveDist /
522 (SPEEDOFSOUNDMETRESPERSEC *
523 Slot->effect.Reverb.DecayTime) *
524 -60.0 / 20.0);
526 WetGainHF[i] *= aluPow(10.0f,
527 log10(Slot->effect.Reverb.AirAbsorptionGainHF) *
528 ALSource->AirAbsorptionFactor * effectiveDist);
531 else
533 /* If the slot's auxiliary send auto is off, the data sent to the
534 * effect slot is the same as the dry path, sans filter effects */
535 WetGain[i] = DryMix;
536 WetGainHF[i] = DryGainHF;
539 switch(ALSource->Send[i].WetFilter.type)
541 case AL_FILTER_LOWPASS:
542 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
543 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
544 break;
546 ALSource->Params.WetGains[i] = WetGain[i] * ListenerGain;
548 for(i = NumSends;i < MAX_SENDS;i++)
550 ALSource->Params.WetGains[i] = 0.0f;
551 WetGainHF[i] = 1.0f;
554 // Apply filter gains and filters
555 switch(ALSource->DirectFilter.type)
557 case AL_FILTER_LOWPASS:
558 DryMix *= ALSource->DirectFilter.Gain;
559 DryGainHF *= ALSource->DirectFilter.GainHF;
560 break;
562 DryMix *= ListenerGain;
564 // Calculate Velocity
565 if(DopplerFactor != 0.0f)
567 ALfloat flVSS, flVLS;
568 ALfloat flMaxVelocity = (DopplerVelocity * flSpeedOfSound) /
569 DopplerFactor;
571 flVSS = aluDotproduct(Velocity, SourceToListener);
572 if(flVSS >= flMaxVelocity)
573 flVSS = (flMaxVelocity - 1.0f);
574 else if(flVSS <= -flMaxVelocity)
575 flVSS = -flMaxVelocity + 1.0f;
577 flVLS = aluDotproduct(ListenerVel, SourceToListener);
578 if(flVLS >= flMaxVelocity)
579 flVLS = (flMaxVelocity - 1.0f);
580 else if(flVLS <= -flMaxVelocity)
581 flVLS = -flMaxVelocity + 1.0f;
583 Pitch = ALSource->flPitch *
584 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVLS)) /
585 ((flSpeedOfSound * DopplerVelocity) - (DopplerFactor * flVSS));
587 else
588 Pitch = ALSource->flPitch;
590 BufferListItem = ALSource->queue;
591 while(BufferListItem != NULL)
593 ALbuffer *ALBuffer;
594 if((ALBuffer=BufferListItem->buffer) != NULL)
596 Pitch = Pitch * ALBuffer->frequency / Frequency;
597 break;
599 BufferListItem = BufferListItem->next;
602 if(Pitch > (float)MAX_PITCH)
603 ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS;
604 else if(!(Pitch > 0.0f))
605 ALSource->Params.Step = 1<<FRACTIONBITS;
606 else
608 ALSource->Params.Step = Pitch*(1<<FRACTIONBITS);
609 if(ALSource->Params.Step == 0)
610 ALSource->Params.Step = 1;
613 // Use energy-preserving panning algorithm for multi-speaker playback
614 length = __max(OrigDist, MinDist);
615 if(length > 0.0f)
617 ALfloat invlen = 1.0f/length;
618 Position[0] *= invlen;
619 Position[1] *= invlen;
620 Position[2] *= invlen;
623 pos = aluCart2LUTpos(-Position[2], Position[0]);
624 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
626 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
627 // elevation adjustment for directional gain. this sucks, but
628 // has low complexity
629 AmbientGain = 1.0/aluSqrt(Device->NumChan) * (1.0-DirGain);
630 for(s = 0;s < OUTPUTCHANNELS;s++)
631 ALSource->Params.DryGains[s] = 0.0f;
632 for(s = 0;s < (ALsizei)Device->NumChan;s++)
634 Channel chan = Device->Speaker2Chan[s];
635 ALfloat gain = SpeakerGain[chan]*DirGain + AmbientGain;
636 ALSource->Params.DryGains[chan] = DryMix * gain;
639 /* Update filter coefficients. */
640 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
642 /* Spatialized sources use four chained one-pole filters, so we need to
643 * take the fourth root of the squared gain, which is the same as the
644 * square root of the base gain. */
645 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
647 for(i = 0;i < NumSends;i++)
649 /* The wet path uses two chained one-pole filters, so take the
650 * base gain (square root of the squared gain) */
651 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
656 ALvoid aluHandleDisconnect(ALCdevice *device)
658 ALuint i;
660 SuspendContext(NULL);
661 for(i = 0;i < device->NumContexts;i++)
663 ALCcontext *Context = device->Contexts[i];
664 ALsource *source;
665 ALsizei pos;
667 SuspendContext(Context);
669 for(pos = 0;pos < Context->SourceMap.size;pos++)
671 source = Context->SourceMap.array[pos].value;
672 if(source->state == AL_PLAYING)
674 source->state = AL_STOPPED;
675 source->BuffersPlayed = source->BuffersInQueue;
676 source->position = 0;
677 source->position_fraction = 0;
680 ProcessContext(Context);
683 device->Connected = ALC_FALSE;
684 ProcessContext(NULL);