Slightly improve channel gain calculations
[openal-soft.git] / Alc / ALu.c
blobb7471132fb71575291426830ba5397ba814ea357
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.Send[i].WetGain = WetGain[i] * ListenerGain;
236 /* Update filter coefficients. Calculations based on the I3DL2
237 * spec. */
238 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
240 /* We use two chained one-pole filters, so we need to take the
241 * square root of the squared gain, which is the same as the base
242 * gain. */
243 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
245 for(i = 0;i < NumSends;i++)
247 /* We use a one-pole filter, so we need to take the squared gain */
248 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
249 ALSource->Params.Send[i].iirFilter.coeff = a;
253 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
255 const ALCdevice *Device = ALContext->Device;
256 ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
257 ALfloat Direction[3],Position[3],SourceToListener[3];
258 ALfloat Velocity[3],ListenerVel[3];
259 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
260 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
261 ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
262 ALfloat AirAbsorptionFactor;
263 ALbufferlistitem *BufferListItem;
264 ALfloat Attenuation, EffectiveDist;
265 ALfloat RoomAttenuation[MAX_SENDS];
266 ALfloat MetersPerUnit;
267 ALfloat RoomRolloff[MAX_SENDS];
268 ALfloat DryGain;
269 ALfloat DryGainHF;
270 ALfloat WetGain[MAX_SENDS];
271 ALfloat WetGainHF[MAX_SENDS];
272 ALfloat DirGain, AmbientGain;
273 const ALfloat *SpeakerGain;
274 ALfloat Pitch;
275 ALfloat length;
276 ALuint Frequency;
277 ALint NumSends;
278 ALint pos, s, i;
279 ALfloat cw;
281 DryGainHF = 1.0f;
282 for(i = 0;i < MAX_SENDS;i++)
283 WetGainHF[i] = 1.0f;
285 //Get context properties
286 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
287 DopplerVelocity = ALContext->DopplerVelocity;
288 SpeedOfSound = ALContext->flSpeedOfSound;
289 NumSends = Device->NumAuxSends;
290 Frequency = Device->Frequency;
292 //Get listener properties
293 ListenerGain = ALContext->Listener.Gain;
294 MetersPerUnit = ALContext->Listener.MetersPerUnit;
295 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
297 //Get source properties
298 SourceVolume = ALSource->flGain;
299 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
300 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
301 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
302 MinVolume = ALSource->flMinGain;
303 MaxVolume = ALSource->flMaxGain;
304 MinDist = ALSource->flRefDistance;
305 MaxDist = ALSource->flMaxDistance;
306 Rolloff = ALSource->flRollOffFactor;
307 InnerAngle = ALSource->flInnerAngle;
308 OuterAngle = ALSource->flOuterAngle;
309 OuterGainHF = ALSource->OuterGainHF;
310 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
312 //1. Translate Listener to origin (convert to head relative)
313 if(ALSource->bHeadRelative == AL_FALSE)
315 ALfloat U[3],V[3],N[3];
316 ALfloat Matrix[4][4];
318 // Build transform matrix
319 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
320 aluNormalize(N); // Normalized At-vector
321 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
322 aluNormalize(V); // Normalized Up-vector
323 aluCrossproduct(N, V, U); // Right-vector
324 aluNormalize(U); // Normalized Right-vector
325 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
326 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
327 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
328 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
330 // Translate position
331 Position[0] -= ALContext->Listener.Position[0];
332 Position[1] -= ALContext->Listener.Position[1];
333 Position[2] -= ALContext->Listener.Position[2];
335 // Transform source position and direction into listener space
336 aluMatrixVector(Position, 1.0f, Matrix);
337 aluMatrixVector(Direction, 0.0f, Matrix);
338 // Transform source and listener velocity into listener space
339 aluMatrixVector(Velocity, 0.0f, Matrix);
340 aluMatrixVector(ListenerVel, 0.0f, Matrix);
342 else
343 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
345 SourceToListener[0] = -Position[0];
346 SourceToListener[1] = -Position[1];
347 SourceToListener[2] = -Position[2];
348 aluNormalize(SourceToListener);
349 aluNormalize(Direction);
351 //2. Calculate distance attenuation
352 Distance = aluSqrt(aluDotproduct(Position, Position));
353 OrigDist = Distance;
355 Attenuation = 1.0f;
356 for(i = 0;i < NumSends;i++)
358 RoomAttenuation[i] = 1.0f;
360 RoomRolloff[i] = ALSource->RoomRolloffFactor;
361 if(ALSource->Send[i].Slot &&
362 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
363 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
364 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
367 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
368 ALContext->DistanceModel)
370 case AL_INVERSE_DISTANCE_CLAMPED:
371 Distance=__max(Distance,MinDist);
372 Distance=__min(Distance,MaxDist);
373 if(MaxDist < MinDist)
374 break;
375 //fall-through
376 case AL_INVERSE_DISTANCE:
377 if(MinDist > 0.0f)
379 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
380 Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
381 for(i = 0;i < NumSends;i++)
383 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
384 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
387 break;
389 case AL_LINEAR_DISTANCE_CLAMPED:
390 Distance=__max(Distance,MinDist);
391 Distance=__min(Distance,MaxDist);
392 if(MaxDist < MinDist)
393 break;
394 //fall-through
395 case AL_LINEAR_DISTANCE:
396 if(MaxDist != MinDist)
398 Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
399 Attenuation = __max(Attenuation, 0.0f);
400 for(i = 0;i < NumSends;i++)
402 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
403 RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
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 Attenuation = 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 DryGain = SourceVolume * Attenuation;
429 for(i = 0;i < NumSends;i++)
430 WetGain[i] = SourceVolume * RoomAttenuation[i];
432 EffectiveDist = 0.0f;
433 if(MinDist > 0.0f && Attenuation < 1.0f)
434 EffectiveDist = (MinDist/Attenuation - 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 DryGain *= ConeVolume;
484 if(ALSource->DryGainHFAuto)
485 DryGainHF *= ConeHF;
487 // Clamp to Min/Max Gain
488 DryGain = __min(DryGain,MaxVolume);
489 DryGain = __max(DryGain,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.Send[i].WetGain = 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(Slot->effect.Reverb.AirAbsorptionGainHF,
529 AirAbsorptionFactor * EffectiveDist);
532 else
534 /* If the slot's auxiliary send auto is off, the data sent to the
535 * effect slot is the same as the dry path, sans filter effects */
536 WetGain[i] = DryGain;
537 WetGainHF[i] = DryGainHF;
540 switch(ALSource->Send[i].WetFilter.type)
542 case AL_FILTER_LOWPASS:
543 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
544 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
545 break;
547 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
550 // Apply filter gains and filters
551 switch(ALSource->DirectFilter.type)
553 case AL_FILTER_LOWPASS:
554 DryGain *= ALSource->DirectFilter.Gain;
555 DryGainHF *= ALSource->DirectFilter.GainHF;
556 break;
558 DryGain *= ListenerGain;
560 // Calculate Velocity
561 Pitch = ALSource->flPitch;
562 if(DopplerFactor != 0.0f)
564 ALfloat VSS, VLS;
565 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
566 DopplerFactor;
568 VSS = aluDotproduct(Velocity, SourceToListener);
569 if(VSS >= MaxVelocity)
570 VSS = (MaxVelocity - 1.0f);
571 else if(VSS <= -MaxVelocity)
572 VSS = -MaxVelocity + 1.0f;
574 VLS = aluDotproduct(ListenerVel, SourceToListener);
575 if(VLS >= MaxVelocity)
576 VLS = (MaxVelocity - 1.0f);
577 else if(VLS <= -MaxVelocity)
578 VLS = -MaxVelocity + 1.0f;
580 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
581 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
584 BufferListItem = ALSource->queue;
585 while(BufferListItem != NULL)
587 ALbuffer *ALBuffer;
588 if((ALBuffer=BufferListItem->buffer) != NULL)
590 Pitch = Pitch * ALBuffer->frequency / Frequency;
591 break;
593 BufferListItem = BufferListItem->next;
596 if(Pitch > (float)MAX_PITCH)
597 ALSource->Params.Step = MAX_PITCH<<FRACTIONBITS;
598 else if(!(Pitch > 0.0f))
599 ALSource->Params.Step = 1<<FRACTIONBITS;
600 else
602 ALSource->Params.Step = Pitch*(1<<FRACTIONBITS);
603 if(ALSource->Params.Step == 0)
604 ALSource->Params.Step = 1;
607 // Use energy-preserving panning algorithm for multi-speaker playback
608 length = __max(OrigDist, MinDist);
609 if(length > 0.0f)
611 ALfloat invlen = 1.0f/length;
612 Position[0] *= invlen;
613 Position[1] *= invlen;
614 Position[2] *= invlen;
617 pos = aluCart2LUTpos(-Position[2], Position[0]);
618 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
620 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
621 // elevation adjustment for directional gain. this sucks, but
622 // has low complexity
623 AmbientGain = aluSqrt(1.0/Device->NumChan);
624 for(s = 0;s < OUTPUTCHANNELS;s++)
625 ALSource->Params.DryGains[s] = 0.0f;
626 for(s = 0;s < (ALsizei)Device->NumChan;s++)
628 Channel chan = Device->Speaker2Chan[s];
629 ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
630 ALSource->Params.DryGains[chan] = DryGain * gain;
633 /* Update filter coefficients. */
634 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
636 /* Spatialized sources use four chained one-pole filters, so we need to
637 * take the fourth root of the squared gain, which is the same as the
638 * square root of the base gain. */
639 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
641 for(i = 0;i < NumSends;i++)
643 /* The wet path uses two chained one-pole filters, so take the
644 * base gain (square root of the squared gain) */
645 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
650 static __inline ALfloat aluF2F(ALfloat Value)
652 return Value;
654 static __inline ALshort aluF2S(ALfloat Value)
656 ALint i;
658 if(Value <= -1.0f) i = -32768;
659 else if(Value >= 1.0f) i = 32767;
660 else i = (ALint)(Value*32767.0f);
662 return ((ALshort)i);
664 static __inline ALubyte aluF2UB(ALfloat Value)
666 ALshort i = aluF2S(Value);
667 return (i>>8)+128;
670 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
672 ALuint SamplesToDo;
673 ALeffectslot *ALEffectSlot;
674 ALCcontext **ctx, **ctx_end;
675 ALsource **src, **src_end;
676 int fpuState;
677 ALuint i, j, c;
678 ALsizei e;
680 #if defined(HAVE_FESETROUND)
681 fpuState = fegetround();
682 fesetround(FE_TOWARDZERO);
683 #elif defined(HAVE__CONTROLFP)
684 fpuState = _controlfp(_RC_CHOP, _MCW_RC);
685 #else
686 (void)fpuState;
687 #endif
689 while(size > 0)
691 /* Setup variables */
692 SamplesToDo = min(size, BUFFERSIZE);
694 /* Clear mixing buffer */
695 memset(device->DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
697 SuspendContext(NULL);
698 ctx = device->Contexts;
699 ctx_end = ctx + device->NumContexts;
700 while(ctx != ctx_end)
702 SuspendContext(*ctx);
704 src = (*ctx)->ActiveSources;
705 src_end = src + (*ctx)->ActiveSourceCount;
706 while(src != src_end)
708 if((*src)->state != AL_PLAYING)
710 --((*ctx)->ActiveSourceCount);
711 *src = *(--src_end);
712 continue;
715 if((*src)->NeedsUpdate)
717 ALsource_Update(*src, *ctx);
718 (*src)->NeedsUpdate = AL_FALSE;
721 MixSource(*src, device, SamplesToDo);
722 src++;
725 /* effect slot processing */
726 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
728 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
730 for(i = 0;i < SamplesToDo;i++)
732 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
733 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
735 for(i = 0;i < 1;i++)
737 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
738 ALEffectSlot->PendingClicks[i] = 0.0f;
741 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
742 SamplesToDo, ALEffectSlot->WetBuffer,
743 device->DryBuffer);
745 for(i = 0;i < SamplesToDo;i++)
746 ALEffectSlot->WetBuffer[i] = 0.0f;
749 ProcessContext(*ctx);
750 ctx++;
752 ProcessContext(NULL);
754 //Post processing loop
755 for(i = 0;i < SamplesToDo;i++)
757 for(c = 0;c < OUTPUTCHANNELS;c++)
759 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
760 device->DryBuffer[i][c] += device->ClickRemoval[c];
763 for(i = 0;i < OUTPUTCHANNELS;i++)
765 device->ClickRemoval[i] += device->PendingClicks[i];
766 device->PendingClicks[i] = 0.0f;
769 switch(device->Format)
771 #define DO_WRITE(T, func, N, ...) do { \
772 const Channel chans[] = { \
773 __VA_ARGS__ \
774 }; \
775 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
776 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
777 const ALuint *ChanMap = device->DevChannels; \
779 for(i = 0;i < SamplesToDo;i++) \
781 for(j = 0;j < N;j++) \
783 ALfloat samp = 0.0f; \
784 for(c = 0;c < OUTPUTCHANNELS;c++) \
785 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
786 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
788 buffer = ((T*)buffer) + N; \
790 } while(0)
792 #define CHECK_WRITE_FORMAT(bits, T, func) \
793 case AL_FORMAT_MONO##bits: \
794 DO_WRITE(T, func, 1, FRONT_CENTER); \
795 break; \
796 case AL_FORMAT_STEREO##bits: \
797 if(device->Bs2b) \
799 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
800 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
801 const ALuint *ChanMap = device->DevChannels; \
803 for(i = 0;i < SamplesToDo;i++) \
805 float samples[2] = { 0.0f, 0.0f }; \
806 for(c = 0;c < OUTPUTCHANNELS;c++) \
808 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
809 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
811 bs2b_cross_feed(device->Bs2b, samples); \
812 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
813 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
814 buffer = ((T*)buffer) + 2; \
817 else \
818 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
819 break; \
820 case AL_FORMAT_QUAD##bits: \
821 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
822 BACK_LEFT, BACK_RIGHT); \
823 break; \
824 case AL_FORMAT_51CHN##bits: \
825 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
826 FRONT_CENTER, LFE, \
827 BACK_LEFT, BACK_RIGHT); \
828 break; \
829 case AL_FORMAT_61CHN##bits: \
830 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
831 FRONT_CENTER, LFE, BACK_CENTER, \
832 SIDE_LEFT, SIDE_RIGHT); \
833 break; \
834 case AL_FORMAT_71CHN##bits: \
835 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
836 FRONT_CENTER, LFE, \
837 BACK_LEFT, BACK_RIGHT, \
838 SIDE_LEFT, SIDE_RIGHT); \
839 break;
841 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
842 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
843 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
844 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
845 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
846 #undef AL_FORMAT_STEREO32
847 #undef AL_FORMAT_MONO32
848 #undef CHECK_WRITE_FORMAT
849 #undef DO_WRITE
851 default:
852 break;
855 size -= SamplesToDo;
858 #if defined(HAVE_FESETROUND)
859 fesetround(fpuState);
860 #elif defined(HAVE__CONTROLFP)
861 _controlfp(fpuState, _MCW_RC);
862 #endif
866 ALvoid aluHandleDisconnect(ALCdevice *device)
868 ALuint i;
870 SuspendContext(NULL);
871 for(i = 0;i < device->NumContexts;i++)
873 ALCcontext *Context = device->Contexts[i];
874 ALsource *source;
875 ALsizei pos;
877 SuspendContext(Context);
879 for(pos = 0;pos < Context->SourceMap.size;pos++)
881 source = Context->SourceMap.array[pos].value;
882 if(source->state == AL_PLAYING)
884 source->state = AL_STOPPED;
885 source->BuffersPlayed = source->BuffersInQueue;
886 source->position = 0;
887 source->position_fraction = 0;
890 ProcessContext(Context);
893 device->Connected = ALC_FALSE;
894 ProcessContext(NULL);