Make sure the muLaw sample encoder is inlined
[openal-soft.git] / Alc / ALu.c
blob43178d660c77b9b3af180980d8f10563a87d2b9e
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 ALuint aluBytesFromFormat(ALenum format)
42 switch(format)
44 case AL_FORMAT_MONO8:
45 case AL_FORMAT_STEREO8:
46 case AL_FORMAT_QUAD8_LOKI:
47 case AL_FORMAT_QUAD8:
48 case AL_FORMAT_REAR8:
49 case AL_FORMAT_51CHN8:
50 case AL_FORMAT_61CHN8:
51 case AL_FORMAT_71CHN8:
52 return 1;
54 case AL_FORMAT_MONO16:
55 case AL_FORMAT_STEREO16:
56 case AL_FORMAT_QUAD16_LOKI:
57 case AL_FORMAT_QUAD16:
58 case AL_FORMAT_REAR16:
59 case AL_FORMAT_51CHN16:
60 case AL_FORMAT_61CHN16:
61 case AL_FORMAT_71CHN16:
62 return 2;
64 case AL_FORMAT_MONO_FLOAT32:
65 case AL_FORMAT_STEREO_FLOAT32:
66 case AL_FORMAT_QUAD32:
67 case AL_FORMAT_REAR32:
68 case AL_FORMAT_51CHN32:
69 case AL_FORMAT_61CHN32:
70 case AL_FORMAT_71CHN32:
71 return 4;
73 case AL_FORMAT_MONO_DOUBLE_EXT:
74 case AL_FORMAT_STEREO_DOUBLE_EXT:
75 return 8;
77 case AL_FORMAT_MONO_MULAW:
78 case AL_FORMAT_STEREO_MULAW:
79 case AL_FORMAT_QUAD_MULAW:
80 case AL_FORMAT_REAR_MULAW:
81 case AL_FORMAT_51CHN_MULAW:
82 case AL_FORMAT_61CHN_MULAW:
83 case AL_FORMAT_71CHN_MULAW:
84 return 1;
86 default:
87 return 0;
90 ALuint aluChannelsFromFormat(ALenum format)
92 switch(format)
94 case AL_FORMAT_MONO8:
95 case AL_FORMAT_MONO16:
96 case AL_FORMAT_MONO_FLOAT32:
97 case AL_FORMAT_MONO_DOUBLE_EXT:
98 case AL_FORMAT_MONO_MULAW:
99 return 1;
101 case AL_FORMAT_STEREO8:
102 case AL_FORMAT_STEREO16:
103 case AL_FORMAT_STEREO_FLOAT32:
104 case AL_FORMAT_STEREO_DOUBLE_EXT:
105 case AL_FORMAT_STEREO_MULAW:
106 return 2;
108 case AL_FORMAT_QUAD8_LOKI:
109 case AL_FORMAT_QUAD16_LOKI:
110 case AL_FORMAT_QUAD8:
111 case AL_FORMAT_QUAD16:
112 case AL_FORMAT_QUAD32:
113 case AL_FORMAT_QUAD_MULAW:
114 return 4;
116 case AL_FORMAT_REAR8:
117 case AL_FORMAT_REAR16:
118 case AL_FORMAT_REAR32:
119 case AL_FORMAT_REAR_MULAW:
120 return 2;
122 case AL_FORMAT_51CHN8:
123 case AL_FORMAT_51CHN16:
124 case AL_FORMAT_51CHN32:
125 case AL_FORMAT_51CHN_MULAW:
126 return 6;
128 case AL_FORMAT_61CHN8:
129 case AL_FORMAT_61CHN16:
130 case AL_FORMAT_61CHN32:
131 case AL_FORMAT_61CHN_MULAW:
132 return 7;
134 case AL_FORMAT_71CHN8:
135 case AL_FORMAT_71CHN16:
136 case AL_FORMAT_71CHN32:
137 case AL_FORMAT_71CHN_MULAW:
138 return 8;
140 default:
141 return 0;
146 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
148 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
149 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
150 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
153 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
155 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
156 inVector1[2]*inVector2[2];
159 static __inline ALvoid aluNormalize(ALfloat *inVector)
161 ALfloat length, inverse_length;
163 length = aluSqrt(aluDotproduct(inVector, inVector));
164 if(length != 0.0f)
166 inverse_length = 1.0f/length;
167 inVector[0] *= inverse_length;
168 inVector[1] *= inverse_length;
169 inVector[2] *= inverse_length;
173 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
175 ALfloat temp[4] = {
176 vector[0], vector[1], vector[2], w
179 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
180 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
181 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
185 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
187 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
188 ALbufferlistitem *BufferListItem;
189 enum FmtChannels Channels;
190 ALfloat DryGain, DryGainHF;
191 ALfloat WetGain[MAX_SENDS];
192 ALfloat WetGainHF[MAX_SENDS];
193 ALint NumSends, Frequency;
194 ALboolean DupStereo;
195 ALfloat Pitch;
196 ALenum Format;
197 ALfloat cw;
198 ALint i;
200 /* Get device properties */
201 Format = ALContext->Device->Format;
202 DupStereo = ALContext->Device->DuplicateStereo;
203 NumSends = ALContext->Device->NumAuxSends;
204 Frequency = ALContext->Device->Frequency;
206 /* Get listener properties */
207 ListenerGain = ALContext->Listener.Gain;
209 /* Get source properties */
210 SourceVolume = ALSource->flGain;
211 MinVolume = ALSource->flMinGain;
212 MaxVolume = ALSource->flMaxGain;
213 Pitch = ALSource->flPitch;
215 /* Calculate the stepping value */
216 Channels = FmtMono;
217 BufferListItem = ALSource->queue;
218 while(BufferListItem != NULL)
220 ALbuffer *ALBuffer;
221 if((ALBuffer=BufferListItem->buffer) != NULL)
223 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
224 ALBuffer->FmtType);
225 maxstep -= ResamplerPadding[ALSource->Resampler] +
226 ResamplerPrePadding[ALSource->Resampler] + 1;
227 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
229 Pitch = Pitch * ALBuffer->Frequency / Frequency;
230 if(Pitch > (ALfloat)maxstep)
231 ALSource->Params.Step = maxstep<<FRACTIONBITS;
232 else
234 ALSource->Params.Step = Pitch*FRACTIONONE;
235 if(ALSource->Params.Step == 0)
236 ALSource->Params.Step = 1;
239 Channels = ALBuffer->FmtChannels;
240 break;
242 BufferListItem = BufferListItem->next;
245 /* Calculate gains */
246 DryGain = SourceVolume;
247 DryGain = __min(DryGain,MaxVolume);
248 DryGain = __max(DryGain,MinVolume);
249 DryGainHF = 1.0f;
251 switch(ALSource->DirectFilter.type)
253 case AL_FILTER_LOWPASS:
254 DryGain *= ALSource->DirectFilter.Gain;
255 DryGainHF *= ALSource->DirectFilter.GainHF;
256 break;
259 if(Channels == FmtStereo)
261 for(i = 0;i < OUTPUTCHANNELS;i++)
262 ALSource->Params.DryGains[i] = 0.0f;
264 if(DupStereo == AL_FALSE)
266 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
267 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
269 else
271 switch(Format)
273 case AL_FORMAT_MONO8:
274 case AL_FORMAT_MONO16:
275 case AL_FORMAT_MONO_FLOAT32:
276 case AL_FORMAT_STEREO8:
277 case AL_FORMAT_STEREO16:
278 case AL_FORMAT_STEREO_FLOAT32:
279 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
280 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
281 break;
283 case AL_FORMAT_QUAD8:
284 case AL_FORMAT_QUAD16:
285 case AL_FORMAT_QUAD32:
286 case AL_FORMAT_51CHN8:
287 case AL_FORMAT_51CHN16:
288 case AL_FORMAT_51CHN32:
289 DryGain *= aluSqrt(2.0f/4.0f);
290 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
291 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
292 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
293 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
294 break;
296 case AL_FORMAT_61CHN8:
297 case AL_FORMAT_61CHN16:
298 case AL_FORMAT_61CHN32:
299 DryGain *= aluSqrt(2.0f/4.0f);
300 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
301 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
302 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
303 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
304 break;
306 case AL_FORMAT_71CHN8:
307 case AL_FORMAT_71CHN16:
308 case AL_FORMAT_71CHN32:
309 DryGain *= aluSqrt(2.0f/6.0f);
310 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
311 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
312 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
313 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
314 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
315 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
316 break;
318 default:
319 break;
323 else
325 for(i = 0;i < OUTPUTCHANNELS;i++)
326 ALSource->Params.DryGains[i] = DryGain * ListenerGain;
329 for(i = 0;i < NumSends;i++)
331 WetGain[i] = SourceVolume;
332 WetGain[i] = __min(WetGain[i],MaxVolume);
333 WetGain[i] = __max(WetGain[i],MinVolume);
334 WetGainHF[i] = 1.0f;
336 switch(ALSource->Send[i].WetFilter.type)
338 case AL_FILTER_LOWPASS:
339 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
340 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
341 break;
344 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
347 /* Update filter coefficients. Calculations based on the I3DL2
348 * spec. */
349 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
351 /* We use two chained one-pole filters, so we need to take the
352 * square root of the squared gain, which is the same as the base
353 * gain. */
354 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
356 for(i = 0;i < NumSends;i++)
358 /* We use a one-pole filter, so we need to take the squared gain */
359 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
360 ALSource->Params.Send[i].iirFilter.coeff = a;
364 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
366 const ALCdevice *Device = ALContext->Device;
367 ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
368 ALfloat Direction[3],Position[3],SourceToListener[3];
369 ALfloat Velocity[3],ListenerVel[3];
370 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
371 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
372 ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
373 ALfloat AirAbsorptionFactor;
374 ALbufferlistitem *BufferListItem;
375 ALfloat Attenuation, EffectiveDist;
376 ALfloat RoomAttenuation[MAX_SENDS];
377 ALfloat MetersPerUnit;
378 ALfloat RoomRolloff[MAX_SENDS];
379 ALfloat DryGain;
380 ALfloat DryGainHF;
381 ALfloat WetGain[MAX_SENDS];
382 ALfloat WetGainHF[MAX_SENDS];
383 ALfloat DirGain, AmbientGain;
384 const ALfloat *SpeakerGain;
385 ALfloat Pitch;
386 ALfloat length;
387 ALuint Frequency;
388 ALint NumSends;
389 ALint pos, s, i;
390 ALfloat cw;
392 DryGainHF = 1.0f;
393 for(i = 0;i < MAX_SENDS;i++)
394 WetGainHF[i] = 1.0f;
396 //Get context properties
397 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
398 DopplerVelocity = ALContext->DopplerVelocity;
399 SpeedOfSound = ALContext->flSpeedOfSound;
400 NumSends = Device->NumAuxSends;
401 Frequency = Device->Frequency;
403 //Get listener properties
404 ListenerGain = ALContext->Listener.Gain;
405 MetersPerUnit = ALContext->Listener.MetersPerUnit;
406 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
408 //Get source properties
409 SourceVolume = ALSource->flGain;
410 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
411 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
412 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
413 MinVolume = ALSource->flMinGain;
414 MaxVolume = ALSource->flMaxGain;
415 MinDist = ALSource->flRefDistance;
416 MaxDist = ALSource->flMaxDistance;
417 Rolloff = ALSource->flRollOffFactor;
418 InnerAngle = ALSource->flInnerAngle;
419 OuterAngle = ALSource->flOuterAngle;
420 OuterGainHF = ALSource->OuterGainHF;
421 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
423 //1. Translate Listener to origin (convert to head relative)
424 if(ALSource->bHeadRelative == AL_FALSE)
426 ALfloat U[3],V[3],N[3];
427 ALfloat Matrix[4][4];
429 // Build transform matrix
430 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
431 aluNormalize(N); // Normalized At-vector
432 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
433 aluNormalize(V); // Normalized Up-vector
434 aluCrossproduct(N, V, U); // Right-vector
435 aluNormalize(U); // Normalized Right-vector
436 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
437 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
438 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
439 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
441 // Translate position
442 Position[0] -= ALContext->Listener.Position[0];
443 Position[1] -= ALContext->Listener.Position[1];
444 Position[2] -= ALContext->Listener.Position[2];
446 // Transform source position and direction into listener space
447 aluMatrixVector(Position, 1.0f, Matrix);
448 aluMatrixVector(Direction, 0.0f, Matrix);
449 // Transform source and listener velocity into listener space
450 aluMatrixVector(Velocity, 0.0f, Matrix);
451 aluMatrixVector(ListenerVel, 0.0f, Matrix);
453 else
454 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
456 SourceToListener[0] = -Position[0];
457 SourceToListener[1] = -Position[1];
458 SourceToListener[2] = -Position[2];
459 aluNormalize(SourceToListener);
460 aluNormalize(Direction);
462 //2. Calculate distance attenuation
463 Distance = aluSqrt(aluDotproduct(Position, Position));
464 OrigDist = Distance;
466 Attenuation = 1.0f;
467 for(i = 0;i < NumSends;i++)
469 RoomAttenuation[i] = 1.0f;
471 RoomRolloff[i] = ALSource->RoomRolloffFactor;
472 if(ALSource->Send[i].Slot &&
473 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
474 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
475 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
478 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
479 ALContext->DistanceModel)
481 case AL_INVERSE_DISTANCE_CLAMPED:
482 Distance=__max(Distance,MinDist);
483 Distance=__min(Distance,MaxDist);
484 if(MaxDist < MinDist)
485 break;
486 //fall-through
487 case AL_INVERSE_DISTANCE:
488 if(MinDist > 0.0f)
490 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
491 Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
492 for(i = 0;i < NumSends;i++)
494 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
495 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
498 break;
500 case AL_LINEAR_DISTANCE_CLAMPED:
501 Distance=__max(Distance,MinDist);
502 Distance=__min(Distance,MaxDist);
503 if(MaxDist < MinDist)
504 break;
505 //fall-through
506 case AL_LINEAR_DISTANCE:
507 if(MaxDist != MinDist)
509 Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
510 Attenuation = __max(Attenuation, 0.0f);
511 for(i = 0;i < NumSends;i++)
513 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
514 RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
517 break;
519 case AL_EXPONENT_DISTANCE_CLAMPED:
520 Distance=__max(Distance,MinDist);
521 Distance=__min(Distance,MaxDist);
522 if(MaxDist < MinDist)
523 break;
524 //fall-through
525 case AL_EXPONENT_DISTANCE:
526 if(Distance > 0.0f && MinDist > 0.0f)
528 Attenuation = aluPow(Distance/MinDist, -Rolloff);
529 for(i = 0;i < NumSends;i++)
530 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
532 break;
534 case AL_NONE:
535 break;
538 // Source Gain + Attenuation
539 DryGain = SourceVolume * Attenuation;
540 for(i = 0;i < NumSends;i++)
541 WetGain[i] = SourceVolume * RoomAttenuation[i];
543 EffectiveDist = 0.0f;
544 if(MinDist > 0.0f && Attenuation < 1.0f)
545 EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
547 // Distance-based air absorption
548 if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
550 ALfloat absorb;
552 // Absorption calculation is done in dB
553 absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
554 EffectiveDist;
555 // Convert dB to linear gain before applying
556 absorb = aluPow(10.0f, absorb/20.0f);
558 DryGainHF *= absorb;
561 //3. Apply directional soundcones
562 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
563 if(Angle >= InnerAngle && Angle <= OuterAngle)
565 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
566 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
567 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
569 else if(Angle > OuterAngle)
571 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
572 ConeHF = (1.0f+(OuterGainHF-1.0f));
574 else
576 ConeVolume = 1.0f;
577 ConeHF = 1.0f;
580 // Apply some high-frequency attenuation for sources behind the listener
581 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
582 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
583 // the same as SourceToListener[2]
584 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
585 // Sources within the minimum distance attenuate less
586 if(OrigDist < MinDist)
587 Angle *= OrigDist/MinDist;
588 if(Angle > 90.0f)
590 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
591 ConeHF *= 1.0f - (Device->HeadDampen*scale);
594 DryGain *= ConeVolume;
595 if(ALSource->DryGainHFAuto)
596 DryGainHF *= ConeHF;
598 // Clamp to Min/Max Gain
599 DryGain = __min(DryGain,MaxVolume);
600 DryGain = __max(DryGain,MinVolume);
602 for(i = 0;i < NumSends;i++)
604 ALeffectslot *Slot = ALSource->Send[i].Slot;
606 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
608 ALSource->Params.Send[i].WetGain = 0.0f;
609 WetGainHF[i] = 1.0f;
610 continue;
613 if(Slot->AuxSendAuto)
615 if(ALSource->WetGainAuto)
616 WetGain[i] *= ConeVolume;
617 if(ALSource->WetGainHFAuto)
618 WetGainHF[i] *= ConeHF;
620 // Clamp to Min/Max Gain
621 WetGain[i] = __min(WetGain[i],MaxVolume);
622 WetGain[i] = __max(WetGain[i],MinVolume);
624 if(Slot->effect.type == AL_EFFECT_REVERB ||
625 Slot->effect.type == AL_EFFECT_EAXREVERB)
627 /* Apply a decay-time transformation to the wet path, based on
628 * the attenuation of the dry path.
630 * Using the approximate (effective) source to listener
631 * distance, the initial decay of the reverb effect is
632 * calculated and applied to the wet path.
634 WetGain[i] *= aluPow(10.0f, EffectiveDist /
635 (SPEEDOFSOUNDMETRESPERSEC *
636 Slot->effect.Reverb.DecayTime) *
637 -60.0 / 20.0);
639 WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
640 AirAbsorptionFactor * EffectiveDist);
643 else
645 /* If the slot's auxiliary send auto is off, the data sent to the
646 * effect slot is the same as the dry path, sans filter effects */
647 WetGain[i] = DryGain;
648 WetGainHF[i] = DryGainHF;
651 switch(ALSource->Send[i].WetFilter.type)
653 case AL_FILTER_LOWPASS:
654 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
655 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
656 break;
658 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
661 // Apply filter gains and filters
662 switch(ALSource->DirectFilter.type)
664 case AL_FILTER_LOWPASS:
665 DryGain *= ALSource->DirectFilter.Gain;
666 DryGainHF *= ALSource->DirectFilter.GainHF;
667 break;
669 DryGain *= ListenerGain;
671 // Calculate Velocity
672 Pitch = ALSource->flPitch;
673 if(DopplerFactor != 0.0f)
675 ALfloat VSS, VLS;
676 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
677 DopplerFactor;
679 VSS = aluDotproduct(Velocity, SourceToListener);
680 if(VSS >= MaxVelocity)
681 VSS = (MaxVelocity - 1.0f);
682 else if(VSS <= -MaxVelocity)
683 VSS = -MaxVelocity + 1.0f;
685 VLS = aluDotproduct(ListenerVel, SourceToListener);
686 if(VLS >= MaxVelocity)
687 VLS = (MaxVelocity - 1.0f);
688 else if(VLS <= -MaxVelocity)
689 VLS = -MaxVelocity + 1.0f;
691 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
692 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
695 BufferListItem = ALSource->queue;
696 while(BufferListItem != NULL)
698 ALbuffer *ALBuffer;
699 if((ALBuffer=BufferListItem->buffer) != NULL)
701 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
702 ALBuffer->FmtType);
703 maxstep -= ResamplerPadding[ALSource->Resampler] +
704 ResamplerPrePadding[ALSource->Resampler] + 1;
705 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
707 Pitch = Pitch * ALBuffer->Frequency / Frequency;
708 if(Pitch > (ALfloat)maxstep)
709 ALSource->Params.Step = maxstep<<FRACTIONBITS;
710 else
712 ALSource->Params.Step = Pitch*FRACTIONONE;
713 if(ALSource->Params.Step == 0)
714 ALSource->Params.Step = 1;
716 break;
718 BufferListItem = BufferListItem->next;
721 // Use energy-preserving panning algorithm for multi-speaker playback
722 length = __max(OrigDist, MinDist);
723 if(length > 0.0f)
725 ALfloat invlen = 1.0f/length;
726 Position[0] *= invlen;
727 Position[1] *= invlen;
728 Position[2] *= invlen;
731 pos = aluCart2LUTpos(-Position[2], Position[0]);
732 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
734 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
735 // elevation adjustment for directional gain. this sucks, but
736 // has low complexity
737 AmbientGain = aluSqrt(1.0/Device->NumChan);
738 for(s = 0;s < OUTPUTCHANNELS;s++)
739 ALSource->Params.DryGains[s] = 0.0f;
740 for(s = 0;s < (ALsizei)Device->NumChan;s++)
742 Channel chan = Device->Speaker2Chan[s];
743 ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
744 ALSource->Params.DryGains[chan] = DryGain * gain;
747 /* Update filter coefficients. */
748 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
750 /* Spatialized sources use four chained one-pole filters, so we need to
751 * take the fourth root of the squared gain, which is the same as the
752 * square root of the base gain. */
753 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
755 for(i = 0;i < NumSends;i++)
757 /* The wet path uses two chained one-pole filters, so take the
758 * base gain (square root of the squared gain) */
759 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
764 static __inline ALfloat aluF2F(ALfloat Value)
766 return Value;
768 static __inline ALshort aluF2S(ALfloat Value)
770 ALint i;
772 if(Value <= -1.0f) i = -32768;
773 else if(Value >= 1.0f) i = 32767;
774 else i = (ALint)(Value*32767.0f);
776 return ((ALshort)i);
778 static __inline ALubyte aluF2UB(ALfloat Value)
780 ALshort i = aluF2S(Value);
781 return (i>>8)+128;
784 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
786 ALuint SamplesToDo;
787 ALeffectslot *ALEffectSlot;
788 ALCcontext **ctx, **ctx_end;
789 ALsource **src, **src_end;
790 int fpuState;
791 ALuint i, j, c;
792 ALsizei e;
794 #if defined(HAVE_FESETROUND)
795 fpuState = fegetround();
796 fesetround(FE_TOWARDZERO);
797 #elif defined(HAVE__CONTROLFP)
798 fpuState = _controlfp(_RC_CHOP, _MCW_RC);
799 #else
800 (void)fpuState;
801 #endif
803 while(size > 0)
805 /* Setup variables */
806 SamplesToDo = min(size, BUFFERSIZE);
808 /* Clear mixing buffer */
809 memset(device->DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
811 SuspendContext(NULL);
812 ctx = device->Contexts;
813 ctx_end = ctx + device->NumContexts;
814 while(ctx != ctx_end)
816 SuspendContext(*ctx);
818 src = (*ctx)->ActiveSources;
819 src_end = src + (*ctx)->ActiveSourceCount;
820 while(src != src_end)
822 if((*src)->state != AL_PLAYING)
824 --((*ctx)->ActiveSourceCount);
825 *src = *(--src_end);
826 continue;
829 if((*src)->NeedsUpdate)
831 ALsource_Update(*src, *ctx);
832 (*src)->NeedsUpdate = AL_FALSE;
835 MixSource(*src, device, SamplesToDo);
836 src++;
839 /* effect slot processing */
840 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
842 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
844 for(i = 0;i < SamplesToDo;i++)
846 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
847 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
849 for(i = 0;i < 1;i++)
851 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
852 ALEffectSlot->PendingClicks[i] = 0.0f;
855 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
856 SamplesToDo, ALEffectSlot->WetBuffer,
857 device->DryBuffer);
859 for(i = 0;i < SamplesToDo;i++)
860 ALEffectSlot->WetBuffer[i] = 0.0f;
863 ProcessContext(*ctx);
864 ctx++;
866 ProcessContext(NULL);
868 //Post processing loop
869 for(i = 0;i < SamplesToDo;i++)
871 for(c = 0;c < OUTPUTCHANNELS;c++)
873 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
874 device->DryBuffer[i][c] += device->ClickRemoval[c];
877 for(i = 0;i < OUTPUTCHANNELS;i++)
879 device->ClickRemoval[i] += device->PendingClicks[i];
880 device->PendingClicks[i] = 0.0f;
883 switch(device->Format)
885 #define DO_WRITE(T, func, N, ...) do { \
886 const Channel chans[] = { \
887 __VA_ARGS__ \
888 }; \
889 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
890 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
891 const ALuint *ChanMap = device->DevChannels; \
893 for(i = 0;i < SamplesToDo;i++) \
895 for(j = 0;j < N;j++) \
897 ALfloat samp = 0.0f; \
898 for(c = 0;c < OUTPUTCHANNELS;c++) \
899 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
900 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
902 buffer = ((T*)buffer) + N; \
904 } while(0)
906 #define CHECK_WRITE_FORMAT(bits, T, func) \
907 case AL_FORMAT_MONO##bits: \
908 DO_WRITE(T, func, 1, FRONT_CENTER); \
909 break; \
910 case AL_FORMAT_STEREO##bits: \
911 if(device->Bs2b) \
913 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
914 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
915 const ALuint *ChanMap = device->DevChannels; \
917 for(i = 0;i < SamplesToDo;i++) \
919 float samples[2] = { 0.0f, 0.0f }; \
920 for(c = 0;c < OUTPUTCHANNELS;c++) \
922 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
923 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
925 bs2b_cross_feed(device->Bs2b, samples); \
926 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
927 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
928 buffer = ((T*)buffer) + 2; \
931 else \
932 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
933 break; \
934 case AL_FORMAT_QUAD##bits: \
935 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
936 BACK_LEFT, BACK_RIGHT); \
937 break; \
938 case AL_FORMAT_51CHN##bits: \
939 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
940 FRONT_CENTER, LFE, \
941 BACK_LEFT, BACK_RIGHT); \
942 break; \
943 case AL_FORMAT_61CHN##bits: \
944 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
945 FRONT_CENTER, LFE, BACK_CENTER, \
946 SIDE_LEFT, SIDE_RIGHT); \
947 break; \
948 case AL_FORMAT_71CHN##bits: \
949 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
950 FRONT_CENTER, LFE, \
951 BACK_LEFT, BACK_RIGHT, \
952 SIDE_LEFT, SIDE_RIGHT); \
953 break;
955 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
956 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
957 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
958 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
959 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
960 #undef AL_FORMAT_STEREO32
961 #undef AL_FORMAT_MONO32
962 #undef CHECK_WRITE_FORMAT
963 #undef DO_WRITE
965 default:
966 break;
969 size -= SamplesToDo;
972 #if defined(HAVE_FESETROUND)
973 fesetround(fpuState);
974 #elif defined(HAVE__CONTROLFP)
975 _controlfp(fpuState, _MCW_RC);
976 #endif
980 ALvoid aluHandleDisconnect(ALCdevice *device)
982 ALuint i;
984 SuspendContext(NULL);
985 for(i = 0;i < device->NumContexts;i++)
987 ALCcontext *Context = device->Contexts[i];
988 ALsource *source;
989 ALsizei pos;
991 SuspendContext(Context);
993 for(pos = 0;pos < Context->SourceMap.size;pos++)
995 source = Context->SourceMap.array[pos].value;
996 if(source->state == AL_PLAYING)
998 source->state = AL_STOPPED;
999 source->BuffersPlayed = source->BuffersInQueue;
1000 source->position = 0;
1001 source->position_fraction = 0;
1004 ProcessContext(Context);
1007 device->Connected = ALC_FALSE;
1008 ProcessContext(NULL);