Make better use of the type range when converting from float
[openal-soft.git] / Alc / ALu.c
blobe0fd5c9f72b1911badb03a5650080b7c8edb045b
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.h"
40 static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
42 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
43 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
44 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
47 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
49 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
50 inVector1[2]*inVector2[2];
53 static __inline ALvoid aluNormalize(ALfloat *inVector)
55 ALfloat length, inverse_length;
57 length = aluSqrt(aluDotproduct(inVector, inVector));
58 if(length != 0.0f)
60 inverse_length = 1.0f/length;
61 inVector[0] *= inverse_length;
62 inVector[1] *= inverse_length;
63 inVector[2] *= inverse_length;
67 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
69 ALfloat temp[4] = {
70 vector[0], vector[1], vector[2], w
73 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
74 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
75 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
79 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
81 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
82 ALbufferlistitem *BufferListItem;
83 enum DevFmtChannels DevChans;
84 enum FmtChannels Channels;
85 ALfloat DryGain, DryGainHF;
86 ALfloat WetGain[MAX_SENDS];
87 ALfloat WetGainHF[MAX_SENDS];
88 ALint NumSends, Frequency;
89 ALboolean DupStereo;
90 ALfloat Pitch;
91 ALfloat cw;
92 ALint i;
94 /* Get device properties */
95 DevChans = ALContext->Device->FmtChans;
96 DupStereo = ALContext->Device->DuplicateStereo;
97 NumSends = ALContext->Device->NumAuxSends;
98 Frequency = ALContext->Device->Frequency;
100 /* Get listener properties */
101 ListenerGain = ALContext->Listener.Gain;
103 /* Get source properties */
104 SourceVolume = ALSource->flGain;
105 MinVolume = ALSource->flMinGain;
106 MaxVolume = ALSource->flMaxGain;
107 Pitch = ALSource->flPitch;
109 /* Calculate the stepping value */
110 Channels = FmtMono;
111 BufferListItem = ALSource->queue;
112 while(BufferListItem != NULL)
114 ALbuffer *ALBuffer;
115 if((ALBuffer=BufferListItem->buffer) != NULL)
117 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
118 ALBuffer->FmtType);
119 maxstep -= ResamplerPadding[ALSource->Resampler] +
120 ResamplerPrePadding[ALSource->Resampler] + 1;
121 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
123 Pitch = Pitch * ALBuffer->Frequency / Frequency;
124 if(Pitch > (ALfloat)maxstep)
125 ALSource->Params.Step = maxstep<<FRACTIONBITS;
126 else
128 ALSource->Params.Step = Pitch*FRACTIONONE;
129 if(ALSource->Params.Step == 0)
130 ALSource->Params.Step = 1;
133 Channels = ALBuffer->FmtChannels;
134 break;
136 BufferListItem = BufferListItem->next;
139 /* Calculate gains */
140 DryGain = SourceVolume;
141 DryGain = __min(DryGain,MaxVolume);
142 DryGain = __max(DryGain,MinVolume);
143 DryGainHF = 1.0f;
145 switch(ALSource->DirectFilter.type)
147 case AL_FILTER_LOWPASS:
148 DryGain *= ALSource->DirectFilter.Gain;
149 DryGainHF *= ALSource->DirectFilter.GainHF;
150 break;
153 if(Channels == FmtStereo)
155 for(i = 0;i < MAXCHANNELS;i++)
156 ALSource->Params.DryGains[i] = 0.0f;
158 if(DupStereo == AL_FALSE)
160 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
161 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
163 else
165 switch(DevChans)
167 case DevFmtMono:
168 case DevFmtStereo:
169 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
170 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
171 break;
173 case DevFmtQuad:
174 case DevFmtX51:
175 DryGain *= aluSqrt(2.0f/4.0f);
176 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
177 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
178 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
179 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
180 break;
182 case DevFmtX61:
183 DryGain *= aluSqrt(2.0f/4.0f);
184 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
185 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
186 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
187 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
188 break;
190 case DevFmtX71:
191 DryGain *= aluSqrt(2.0f/6.0f);
192 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
193 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
194 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
195 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
196 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
197 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
198 break;
202 else
204 for(i = 0;i < MAXCHANNELS;i++)
205 ALSource->Params.DryGains[i] = DryGain * ListenerGain;
208 for(i = 0;i < NumSends;i++)
210 WetGain[i] = SourceVolume;
211 WetGain[i] = __min(WetGain[i],MaxVolume);
212 WetGain[i] = __max(WetGain[i],MinVolume);
213 WetGainHF[i] = 1.0f;
215 switch(ALSource->Send[i].WetFilter.type)
217 case AL_FILTER_LOWPASS:
218 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
219 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
220 break;
223 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
226 /* Update filter coefficients. Calculations based on the I3DL2
227 * spec. */
228 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
230 /* We use two chained one-pole filters, so we need to take the
231 * square root of the squared gain, which is the same as the base
232 * gain. */
233 ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
235 for(i = 0;i < NumSends;i++)
237 /* We use a one-pole filter, so we need to take the squared gain */
238 ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
239 ALSource->Params.Send[i].iirFilter.coeff = a;
243 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
245 const ALCdevice *Device = ALContext->Device;
246 ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
247 ALfloat Direction[3],Position[3],SourceToListener[3];
248 ALfloat Velocity[3],ListenerVel[3];
249 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
250 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
251 ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
252 ALfloat AirAbsorptionFactor;
253 ALbufferlistitem *BufferListItem;
254 ALfloat Attenuation, EffectiveDist;
255 ALfloat RoomAttenuation[MAX_SENDS];
256 ALfloat MetersPerUnit;
257 ALfloat RoomRolloff[MAX_SENDS];
258 ALfloat DryGain;
259 ALfloat DryGainHF;
260 ALfloat WetGain[MAX_SENDS];
261 ALfloat WetGainHF[MAX_SENDS];
262 ALfloat DirGain, AmbientGain;
263 const ALfloat *SpeakerGain;
264 ALfloat Pitch;
265 ALfloat length;
266 ALuint Frequency;
267 ALint NumSends;
268 ALint pos, s, i;
269 ALfloat cw;
271 DryGainHF = 1.0f;
272 for(i = 0;i < MAX_SENDS;i++)
273 WetGainHF[i] = 1.0f;
275 //Get context properties
276 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
277 DopplerVelocity = ALContext->DopplerVelocity;
278 SpeedOfSound = ALContext->flSpeedOfSound;
279 NumSends = Device->NumAuxSends;
280 Frequency = Device->Frequency;
282 //Get listener properties
283 ListenerGain = ALContext->Listener.Gain;
284 MetersPerUnit = ALContext->Listener.MetersPerUnit;
285 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
287 //Get source properties
288 SourceVolume = ALSource->flGain;
289 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
290 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
291 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
292 MinVolume = ALSource->flMinGain;
293 MaxVolume = ALSource->flMaxGain;
294 MinDist = ALSource->flRefDistance;
295 MaxDist = ALSource->flMaxDistance;
296 Rolloff = ALSource->flRollOffFactor;
297 InnerAngle = ALSource->flInnerAngle;
298 OuterAngle = ALSource->flOuterAngle;
299 OuterGainHF = ALSource->OuterGainHF;
300 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
302 //1. Translate Listener to origin (convert to head relative)
303 if(ALSource->bHeadRelative == AL_FALSE)
305 ALfloat U[3],V[3],N[3];
306 ALfloat Matrix[4][4];
308 // Build transform matrix
309 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
310 aluNormalize(N); // Normalized At-vector
311 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
312 aluNormalize(V); // Normalized Up-vector
313 aluCrossproduct(N, V, U); // Right-vector
314 aluNormalize(U); // Normalized Right-vector
315 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
316 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
317 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
318 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
320 // Translate position
321 Position[0] -= ALContext->Listener.Position[0];
322 Position[1] -= ALContext->Listener.Position[1];
323 Position[2] -= ALContext->Listener.Position[2];
325 // Transform source position and direction into listener space
326 aluMatrixVector(Position, 1.0f, Matrix);
327 aluMatrixVector(Direction, 0.0f, Matrix);
328 // Transform source and listener velocity into listener space
329 aluMatrixVector(Velocity, 0.0f, Matrix);
330 aluMatrixVector(ListenerVel, 0.0f, Matrix);
332 else
333 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
335 SourceToListener[0] = -Position[0];
336 SourceToListener[1] = -Position[1];
337 SourceToListener[2] = -Position[2];
338 aluNormalize(SourceToListener);
339 aluNormalize(Direction);
341 //2. Calculate distance attenuation
342 Distance = aluSqrt(aluDotproduct(Position, Position));
343 OrigDist = Distance;
345 Attenuation = 1.0f;
346 for(i = 0;i < NumSends;i++)
348 RoomAttenuation[i] = 1.0f;
350 RoomRolloff[i] = ALSource->RoomRolloffFactor;
351 if(ALSource->Send[i].Slot &&
352 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
353 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
354 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
357 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
358 ALContext->DistanceModel)
360 case AL_INVERSE_DISTANCE_CLAMPED:
361 Distance=__max(Distance,MinDist);
362 Distance=__min(Distance,MaxDist);
363 if(MaxDist < MinDist)
364 break;
365 //fall-through
366 case AL_INVERSE_DISTANCE:
367 if(MinDist > 0.0f)
369 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
370 Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
371 for(i = 0;i < NumSends;i++)
373 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
374 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
377 break;
379 case AL_LINEAR_DISTANCE_CLAMPED:
380 Distance=__max(Distance,MinDist);
381 Distance=__min(Distance,MaxDist);
382 if(MaxDist < MinDist)
383 break;
384 //fall-through
385 case AL_LINEAR_DISTANCE:
386 if(MaxDist != MinDist)
388 Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
389 Attenuation = __max(Attenuation, 0.0f);
390 for(i = 0;i < NumSends;i++)
392 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
393 RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
396 break;
398 case AL_EXPONENT_DISTANCE_CLAMPED:
399 Distance=__max(Distance,MinDist);
400 Distance=__min(Distance,MaxDist);
401 if(MaxDist < MinDist)
402 break;
403 //fall-through
404 case AL_EXPONENT_DISTANCE:
405 if(Distance > 0.0f && MinDist > 0.0f)
407 Attenuation = aluPow(Distance/MinDist, -Rolloff);
408 for(i = 0;i < NumSends;i++)
409 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
411 break;
413 case AL_NONE:
414 break;
417 // Source Gain + Attenuation
418 DryGain = SourceVolume * Attenuation;
419 for(i = 0;i < NumSends;i++)
420 WetGain[i] = SourceVolume * RoomAttenuation[i];
422 EffectiveDist = 0.0f;
423 if(MinDist > 0.0f && Attenuation < 1.0f)
424 EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
426 // Distance-based air absorption
427 if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
429 ALfloat absorb;
431 // Absorption calculation is done in dB
432 absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
433 EffectiveDist;
434 // Convert dB to linear gain before applying
435 absorb = aluPow(10.0f, absorb/20.0f);
437 DryGainHF *= absorb;
440 //3. Apply directional soundcones
441 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
442 if(Angle >= InnerAngle && Angle <= OuterAngle)
444 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
445 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
446 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
448 else if(Angle > OuterAngle)
450 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
451 ConeHF = (1.0f+(OuterGainHF-1.0f));
453 else
455 ConeVolume = 1.0f;
456 ConeHF = 1.0f;
459 // Apply some high-frequency attenuation for sources behind the listener
460 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
461 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
462 // the same as SourceToListener[2]
463 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
464 // Sources within the minimum distance attenuate less
465 if(OrigDist < MinDist)
466 Angle *= OrigDist/MinDist;
467 if(Angle > 90.0f)
469 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
470 ConeHF *= 1.0f - (Device->HeadDampen*scale);
473 DryGain *= ConeVolume;
474 if(ALSource->DryGainHFAuto)
475 DryGainHF *= ConeHF;
477 // Clamp to Min/Max Gain
478 DryGain = __min(DryGain,MaxVolume);
479 DryGain = __max(DryGain,MinVolume);
481 for(i = 0;i < NumSends;i++)
483 ALeffectslot *Slot = ALSource->Send[i].Slot;
485 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
487 ALSource->Params.Send[i].WetGain = 0.0f;
488 WetGainHF[i] = 1.0f;
489 continue;
492 if(Slot->AuxSendAuto)
494 if(ALSource->WetGainAuto)
495 WetGain[i] *= ConeVolume;
496 if(ALSource->WetGainHFAuto)
497 WetGainHF[i] *= ConeHF;
499 // Clamp to Min/Max Gain
500 WetGain[i] = __min(WetGain[i],MaxVolume);
501 WetGain[i] = __max(WetGain[i],MinVolume);
503 if(Slot->effect.type == AL_EFFECT_REVERB ||
504 Slot->effect.type == AL_EFFECT_EAXREVERB)
506 /* Apply a decay-time transformation to the wet path, based on
507 * the attenuation of the dry path.
509 * Using the approximate (effective) source to listener
510 * distance, the initial decay of the reverb effect is
511 * calculated and applied to the wet path.
513 WetGain[i] *= aluPow(10.0f, EffectiveDist /
514 (SPEEDOFSOUNDMETRESPERSEC *
515 Slot->effect.Reverb.DecayTime) *
516 -60.0 / 20.0);
518 WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
519 AirAbsorptionFactor * EffectiveDist);
522 else
524 /* If the slot's auxiliary send auto is off, the data sent to the
525 * effect slot is the same as the dry path, sans filter effects */
526 WetGain[i] = DryGain;
527 WetGainHF[i] = DryGainHF;
530 switch(ALSource->Send[i].WetFilter.type)
532 case AL_FILTER_LOWPASS:
533 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
534 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
535 break;
537 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
540 // Apply filter gains and filters
541 switch(ALSource->DirectFilter.type)
543 case AL_FILTER_LOWPASS:
544 DryGain *= ALSource->DirectFilter.Gain;
545 DryGainHF *= ALSource->DirectFilter.GainHF;
546 break;
548 DryGain *= ListenerGain;
550 // Calculate Velocity
551 Pitch = ALSource->flPitch;
552 if(DopplerFactor != 0.0f)
554 ALfloat VSS, VLS;
555 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
556 DopplerFactor;
558 VSS = aluDotproduct(Velocity, SourceToListener);
559 if(VSS >= MaxVelocity)
560 VSS = (MaxVelocity - 1.0f);
561 else if(VSS <= -MaxVelocity)
562 VSS = -MaxVelocity + 1.0f;
564 VLS = aluDotproduct(ListenerVel, SourceToListener);
565 if(VLS >= MaxVelocity)
566 VLS = (MaxVelocity - 1.0f);
567 else if(VLS <= -MaxVelocity)
568 VLS = -MaxVelocity + 1.0f;
570 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
571 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
574 BufferListItem = ALSource->queue;
575 while(BufferListItem != NULL)
577 ALbuffer *ALBuffer;
578 if((ALBuffer=BufferListItem->buffer) != NULL)
580 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
581 ALBuffer->FmtType);
582 maxstep -= ResamplerPadding[ALSource->Resampler] +
583 ResamplerPrePadding[ALSource->Resampler] + 1;
584 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
586 Pitch = Pitch * ALBuffer->Frequency / Frequency;
587 if(Pitch > (ALfloat)maxstep)
588 ALSource->Params.Step = maxstep<<FRACTIONBITS;
589 else
591 ALSource->Params.Step = Pitch*FRACTIONONE;
592 if(ALSource->Params.Step == 0)
593 ALSource->Params.Step = 1;
595 break;
597 BufferListItem = BufferListItem->next;
600 // Use energy-preserving panning algorithm for multi-speaker playback
601 length = __max(OrigDist, MinDist);
602 if(length > 0.0f)
604 ALfloat invlen = 1.0f/length;
605 Position[0] *= invlen;
606 Position[1] *= invlen;
607 Position[2] *= invlen;
610 pos = aluCart2LUTpos(-Position[2], Position[0]);
611 SpeakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
613 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
614 // elevation adjustment for directional gain. this sucks, but
615 // has low complexity
616 AmbientGain = aluSqrt(1.0/Device->NumChan);
617 for(s = 0;s < MAXCHANNELS;s++)
618 ALSource->Params.DryGains[s] = 0.0f;
619 for(s = 0;s < (ALsizei)Device->NumChan;s++)
621 Channel chan = Device->Speaker2Chan[s];
622 ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
623 ALSource->Params.DryGains[chan] = DryGain * gain;
626 /* Update filter coefficients. */
627 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
629 /* Spatialized sources use four chained one-pole filters, so we need to
630 * take the fourth root of the squared gain, which is the same as the
631 * square root of the base gain. */
632 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
634 for(i = 0;i < NumSends;i++)
636 /* The wet path uses two chained one-pole filters, so take the
637 * base gain (square root of the squared gain) */
638 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
643 static __inline ALfloat aluF2F(ALfloat val)
645 return val;
647 static __inline ALushort aluF2US(ALfloat val)
649 if(val > 1.0f) return 65535;
650 if(val < -1.0f) return 0;
651 return (ALint)(val*32767.0f) + 32768;
653 static __inline ALshort aluF2S(ALfloat val)
655 if(val > 1.0f) return 32767;
656 if(val < -1.0f) return -32768;
657 return (ALint)(val*32767.0f);
659 static __inline ALubyte aluF2UB(ALfloat val)
661 ALushort i = aluF2US(val);
662 return i>>8;
664 static __inline ALbyte aluF2B(ALfloat val)
666 ALshort i = aluF2S(val);
667 return i>>8;
670 static const Channel MonoChans[] = { FRONT_CENTER };
671 static const Channel StereoChans[] = { FRONT_LEFT, FRONT_RIGHT };
672 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
673 BACK_LEFT, BACK_RIGHT };
674 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
675 FRONT_CENTER, LFE,
676 BACK_LEFT, BACK_RIGHT };
677 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_LEFT,
678 FRONT_CENTER, LFE, BACK_CENTER,
679 SIDE_LEFT, SIDE_RIGHT };
680 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
681 FRONT_CENTER, LFE,
682 BACK_LEFT, BACK_RIGHT,
683 SIDE_LEFT, SIDE_RIGHT };
685 #define DECL_TEMPLATE(T, chans,N, func) \
686 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
688 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
689 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
690 const ALuint *ChanMap = device->DevChannels; \
691 ALuint i, j, c; \
693 for(i = 0;i < SamplesToDo;i++) \
695 for(j = 0;j < N;j++) \
697 ALfloat samp = 0.0f; \
698 for(c = 0;c < MAXCHANNELS;c++) \
699 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
700 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
702 buffer = ((T*)buffer) + N; \
706 DECL_TEMPLATE(ALfloat, MonoChans,1, aluF2F)
707 DECL_TEMPLATE(ALfloat, QuadChans,4, aluF2F)
708 DECL_TEMPLATE(ALfloat, X51Chans,6, aluF2F)
709 DECL_TEMPLATE(ALfloat, X61Chans,7, aluF2F)
710 DECL_TEMPLATE(ALfloat, X71Chans,8, aluF2F)
712 DECL_TEMPLATE(ALushort, MonoChans,1, aluF2US)
713 DECL_TEMPLATE(ALushort, QuadChans,4, aluF2US)
714 DECL_TEMPLATE(ALushort, X51Chans,6, aluF2US)
715 DECL_TEMPLATE(ALushort, X61Chans,7, aluF2US)
716 DECL_TEMPLATE(ALushort, X71Chans,8, aluF2US)
718 DECL_TEMPLATE(ALshort, MonoChans,1, aluF2S)
719 DECL_TEMPLATE(ALshort, QuadChans,4, aluF2S)
720 DECL_TEMPLATE(ALshort, X51Chans,6, aluF2S)
721 DECL_TEMPLATE(ALshort, X61Chans,7, aluF2S)
722 DECL_TEMPLATE(ALshort, X71Chans,8, aluF2S)
724 DECL_TEMPLATE(ALubyte, MonoChans,1, aluF2UB)
725 DECL_TEMPLATE(ALubyte, QuadChans,4, aluF2UB)
726 DECL_TEMPLATE(ALubyte, X51Chans,6, aluF2UB)
727 DECL_TEMPLATE(ALubyte, X61Chans,7, aluF2UB)
728 DECL_TEMPLATE(ALubyte, X71Chans,8, aluF2UB)
730 DECL_TEMPLATE(ALbyte, MonoChans,1, aluF2B)
731 DECL_TEMPLATE(ALbyte, QuadChans,4, aluF2B)
732 DECL_TEMPLATE(ALbyte, X51Chans,6, aluF2B)
733 DECL_TEMPLATE(ALbyte, X61Chans,7, aluF2B)
734 DECL_TEMPLATE(ALbyte, X71Chans,8, aluF2B)
736 #undef DECL_TEMPLATE
738 #define DECL_TEMPLATE(T, chans,N, func) \
739 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
741 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
742 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
743 const ALuint *ChanMap = device->DevChannels; \
744 ALuint i, j, c; \
746 if(device->Bs2b) \
748 for(i = 0;i < SamplesToDo;i++) \
750 float samples[2] = { 0.0f, 0.0f }; \
751 for(c = 0;c < MAXCHANNELS;c++) \
753 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
754 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
756 bs2b_cross_feed(device->Bs2b, samples); \
757 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
758 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
759 buffer = ((T*)buffer) + 2; \
762 else \
764 for(i = 0;i < SamplesToDo;i++) \
766 for(j = 0;j < N;j++) \
768 ALfloat samp = 0.0f; \
769 for(c = 0;c < MAXCHANNELS;c++) \
770 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
771 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
773 buffer = ((T*)buffer) + N; \
778 DECL_TEMPLATE(ALfloat, StereoChans,2, aluF2F)
779 DECL_TEMPLATE(ALushort, StereoChans,2, aluF2US)
780 DECL_TEMPLATE(ALshort, StereoChans,2, aluF2S)
781 DECL_TEMPLATE(ALubyte, StereoChans,2, aluF2UB)
782 DECL_TEMPLATE(ALbyte, StereoChans,2, aluF2B)
784 #undef DECL_TEMPLATE
786 #define DECL_TEMPLATE(T, func) \
787 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
789 switch(device->FmtChans) \
791 case DevFmtMono: \
792 Write_##T##_MonoChans(device, buffer, SamplesToDo); \
793 break; \
794 case DevFmtStereo: \
795 Write_##T##_StereoChans(device, buffer, SamplesToDo); \
796 break; \
797 case DevFmtQuad: \
798 Write_##T##_QuadChans(device, buffer, SamplesToDo); \
799 break; \
800 case DevFmtX51: \
801 Write_##T##_X51Chans(device, buffer, SamplesToDo); \
802 break; \
803 case DevFmtX61: \
804 Write_##T##_X61Chans(device, buffer, SamplesToDo); \
805 break; \
806 case DevFmtX71: \
807 Write_##T##_X71Chans(device, buffer, SamplesToDo); \
808 break; \
812 DECL_TEMPLATE(ALfloat, aluF2F)
813 DECL_TEMPLATE(ALushort, aluF2US)
814 DECL_TEMPLATE(ALshort, aluF2S)
815 DECL_TEMPLATE(ALubyte, aluF2UB)
816 DECL_TEMPLATE(ALbyte, aluF2B)
818 #undef DECL_TEMPLATE
820 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
822 ALuint SamplesToDo;
823 ALeffectslot *ALEffectSlot;
824 ALCcontext **ctx, **ctx_end;
825 ALsource **src, **src_end;
826 int fpuState;
827 ALuint i, c;
828 ALsizei e;
830 #if defined(HAVE_FESETROUND)
831 fpuState = fegetround();
832 fesetround(FE_TOWARDZERO);
833 #elif defined(HAVE__CONTROLFP)
834 fpuState = _controlfp(_RC_CHOP, _MCW_RC);
835 #else
836 (void)fpuState;
837 #endif
839 while(size > 0)
841 /* Setup variables */
842 SamplesToDo = min(size, BUFFERSIZE);
844 /* Clear mixing buffer */
845 memset(device->DryBuffer, 0, SamplesToDo*MAXCHANNELS*sizeof(ALfloat));
847 SuspendContext(NULL);
848 ctx = device->Contexts;
849 ctx_end = ctx + device->NumContexts;
850 while(ctx != ctx_end)
852 SuspendContext(*ctx);
854 src = (*ctx)->ActiveSources;
855 src_end = src + (*ctx)->ActiveSourceCount;
856 while(src != src_end)
858 if((*src)->state != AL_PLAYING)
860 --((*ctx)->ActiveSourceCount);
861 *src = *(--src_end);
862 continue;
865 if((*src)->NeedsUpdate)
867 ALsource_Update(*src, *ctx);
868 (*src)->NeedsUpdate = AL_FALSE;
871 MixSource(*src, device, SamplesToDo);
872 src++;
875 /* effect slot processing */
876 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
878 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
880 for(i = 0;i < SamplesToDo;i++)
882 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
883 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
885 for(i = 0;i < 1;i++)
887 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
888 ALEffectSlot->PendingClicks[i] = 0.0f;
891 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
892 SamplesToDo, ALEffectSlot->WetBuffer,
893 device->DryBuffer);
895 for(i = 0;i < SamplesToDo;i++)
896 ALEffectSlot->WetBuffer[i] = 0.0f;
899 ProcessContext(*ctx);
900 ctx++;
902 ProcessContext(NULL);
904 //Post processing loop
905 for(i = 0;i < SamplesToDo;i++)
907 for(c = 0;c < MAXCHANNELS;c++)
909 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
910 device->DryBuffer[i][c] += device->ClickRemoval[c];
913 for(i = 0;i < MAXCHANNELS;i++)
915 device->ClickRemoval[i] += device->PendingClicks[i];
916 device->PendingClicks[i] = 0.0f;
919 switch(device->FmtType)
921 case DevFmtByte:
922 Write_ALbyte(device, buffer, SamplesToDo);
923 break;
924 case DevFmtUByte:
925 Write_ALubyte(device, buffer, SamplesToDo);
926 break;
927 case DevFmtShort:
928 Write_ALshort(device, buffer, SamplesToDo);
929 break;
930 case DevFmtUShort:
931 Write_ALushort(device, buffer, SamplesToDo);
932 break;
933 case DevFmtFloat:
934 Write_ALfloat(device, buffer, SamplesToDo);
935 break;
938 size -= SamplesToDo;
941 #if defined(HAVE_FESETROUND)
942 fesetround(fpuState);
943 #elif defined(HAVE__CONTROLFP)
944 _controlfp(fpuState, _MCW_RC);
945 #endif
949 ALvoid aluHandleDisconnect(ALCdevice *device)
951 ALuint i;
953 SuspendContext(NULL);
954 for(i = 0;i < device->NumContexts;i++)
956 ALCcontext *Context = device->Contexts[i];
957 ALsource *source;
958 ALsizei pos;
960 SuspendContext(Context);
962 for(pos = 0;pos < Context->SourceMap.size;pos++)
964 source = Context->SourceMap.array[pos].value;
965 if(source->state == AL_PLAYING)
967 source->state = AL_STOPPED;
968 source->BuffersPlayed = source->BuffersInQueue;
969 source->position = 0;
970 source->position_fraction = 0;
973 ProcessContext(Context);
976 device->Connected = ALC_FALSE;
977 ProcessContext(NULL);