Don't store the internal format in the buffer
[openal-soft.git] / Alc / ALu.c
blob3a635826d1b15fc5def7e8685984febebe4cfdee
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 FmtChannels Channels;
84 ALfloat DryGain, DryGainHF;
85 ALfloat WetGain[MAX_SENDS];
86 ALfloat WetGainHF[MAX_SENDS];
87 ALint NumSends, Frequency;
88 ALboolean DupStereo;
89 ALfloat Pitch;
90 ALenum Format;
91 ALfloat cw;
92 ALint i;
94 /* Get device 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;
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->FmtType,
118 ALBuffer->FmtChannels);
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 < OUTPUTCHANNELS;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(Format)
167 case AL_FORMAT_MONO8:
168 case AL_FORMAT_MONO16:
169 case AL_FORMAT_MONO_FLOAT32:
170 case AL_FORMAT_STEREO8:
171 case AL_FORMAT_STEREO16:
172 case AL_FORMAT_STEREO_FLOAT32:
173 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
174 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
175 break;
177 case AL_FORMAT_QUAD8:
178 case AL_FORMAT_QUAD16:
179 case AL_FORMAT_QUAD32:
180 case AL_FORMAT_51CHN8:
181 case AL_FORMAT_51CHN16:
182 case AL_FORMAT_51CHN32:
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[BACK_LEFT] = DryGain * ListenerGain;
187 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
188 break;
190 case AL_FORMAT_61CHN8:
191 case AL_FORMAT_61CHN16:
192 case AL_FORMAT_61CHN32:
193 DryGain *= aluSqrt(2.0f/4.0f);
194 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
195 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
196 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
197 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
198 break;
200 case AL_FORMAT_71CHN8:
201 case AL_FORMAT_71CHN16:
202 case AL_FORMAT_71CHN32:
203 DryGain *= aluSqrt(2.0f/6.0f);
204 ALSource->Params.DryGains[FRONT_LEFT] = DryGain * ListenerGain;
205 ALSource->Params.DryGains[FRONT_RIGHT] = DryGain * ListenerGain;
206 ALSource->Params.DryGains[BACK_LEFT] = DryGain * ListenerGain;
207 ALSource->Params.DryGains[BACK_RIGHT] = DryGain * ListenerGain;
208 ALSource->Params.DryGains[SIDE_LEFT] = DryGain * ListenerGain;
209 ALSource->Params.DryGains[SIDE_RIGHT] = DryGain * ListenerGain;
210 break;
212 default:
213 break;
217 else
219 for(i = 0;i < OUTPUTCHANNELS;i++)
220 ALSource->Params.DryGains[i] = DryGain * ListenerGain;
223 for(i = 0;i < NumSends;i++)
225 WetGain[i] = SourceVolume;
226 WetGain[i] = __min(WetGain[i],MaxVolume);
227 WetGain[i] = __max(WetGain[i],MinVolume);
228 WetGainHF[i] = 1.0f;
230 switch(ALSource->Send[i].WetFilter.type)
232 case AL_FILTER_LOWPASS:
233 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
234 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
235 break;
238 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
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,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, SpeedOfSound;
267 ALfloat AirAbsorptionFactor;
268 ALbufferlistitem *BufferListItem;
269 ALfloat Attenuation, EffectiveDist;
270 ALfloat RoomAttenuation[MAX_SENDS];
271 ALfloat MetersPerUnit;
272 ALfloat RoomRolloff[MAX_SENDS];
273 ALfloat DryGain;
274 ALfloat DryGainHF;
275 ALfloat WetGain[MAX_SENDS];
276 ALfloat WetGainHF[MAX_SENDS];
277 ALfloat DirGain, AmbientGain;
278 const ALfloat *SpeakerGain;
279 ALfloat Pitch;
280 ALfloat length;
281 ALuint Frequency;
282 ALint NumSends;
283 ALint pos, s, i;
284 ALfloat cw;
286 DryGainHF = 1.0f;
287 for(i = 0;i < MAX_SENDS;i++)
288 WetGainHF[i] = 1.0f;
290 //Get context properties
291 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
292 DopplerVelocity = ALContext->DopplerVelocity;
293 SpeedOfSound = ALContext->flSpeedOfSound;
294 NumSends = Device->NumAuxSends;
295 Frequency = Device->Frequency;
297 //Get listener properties
298 ListenerGain = ALContext->Listener.Gain;
299 MetersPerUnit = ALContext->Listener.MetersPerUnit;
300 memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
302 //Get source properties
303 SourceVolume = ALSource->flGain;
304 memcpy(Position, ALSource->vPosition, sizeof(ALSource->vPosition));
305 memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
306 memcpy(Velocity, ALSource->vVelocity, sizeof(ALSource->vVelocity));
307 MinVolume = ALSource->flMinGain;
308 MaxVolume = ALSource->flMaxGain;
309 MinDist = ALSource->flRefDistance;
310 MaxDist = ALSource->flMaxDistance;
311 Rolloff = ALSource->flRollOffFactor;
312 InnerAngle = ALSource->flInnerAngle;
313 OuterAngle = ALSource->flOuterAngle;
314 OuterGainHF = ALSource->OuterGainHF;
315 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
317 //1. Translate Listener to origin (convert to head relative)
318 if(ALSource->bHeadRelative == AL_FALSE)
320 ALfloat U[3],V[3],N[3];
321 ALfloat Matrix[4][4];
323 // Build transform matrix
324 memcpy(N, ALContext->Listener.Forward, sizeof(N)); // At-vector
325 aluNormalize(N); // Normalized At-vector
326 memcpy(V, ALContext->Listener.Up, sizeof(V)); // Up-vector
327 aluNormalize(V); // Normalized Up-vector
328 aluCrossproduct(N, V, U); // Right-vector
329 aluNormalize(U); // Normalized Right-vector
330 Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
331 Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
332 Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
333 Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] = 0.0f; Matrix[3][3] = 1.0f;
335 // Translate position
336 Position[0] -= ALContext->Listener.Position[0];
337 Position[1] -= ALContext->Listener.Position[1];
338 Position[2] -= ALContext->Listener.Position[2];
340 // Transform source position and direction into listener space
341 aluMatrixVector(Position, 1.0f, Matrix);
342 aluMatrixVector(Direction, 0.0f, Matrix);
343 // Transform source and listener velocity into listener space
344 aluMatrixVector(Velocity, 0.0f, Matrix);
345 aluMatrixVector(ListenerVel, 0.0f, Matrix);
347 else
348 ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
350 SourceToListener[0] = -Position[0];
351 SourceToListener[1] = -Position[1];
352 SourceToListener[2] = -Position[2];
353 aluNormalize(SourceToListener);
354 aluNormalize(Direction);
356 //2. Calculate distance attenuation
357 Distance = aluSqrt(aluDotproduct(Position, Position));
358 OrigDist = Distance;
360 Attenuation = 1.0f;
361 for(i = 0;i < NumSends;i++)
363 RoomAttenuation[i] = 1.0f;
365 RoomRolloff[i] = ALSource->RoomRolloffFactor;
366 if(ALSource->Send[i].Slot &&
367 (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
368 ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
369 RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
372 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
373 ALContext->DistanceModel)
375 case AL_INVERSE_DISTANCE_CLAMPED:
376 Distance=__max(Distance,MinDist);
377 Distance=__min(Distance,MaxDist);
378 if(MaxDist < MinDist)
379 break;
380 //fall-through
381 case AL_INVERSE_DISTANCE:
382 if(MinDist > 0.0f)
384 if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
385 Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
386 for(i = 0;i < NumSends;i++)
388 if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
389 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
392 break;
394 case AL_LINEAR_DISTANCE_CLAMPED:
395 Distance=__max(Distance,MinDist);
396 Distance=__min(Distance,MaxDist);
397 if(MaxDist < MinDist)
398 break;
399 //fall-through
400 case AL_LINEAR_DISTANCE:
401 if(MaxDist != MinDist)
403 Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
404 Attenuation = __max(Attenuation, 0.0f);
405 for(i = 0;i < NumSends;i++)
407 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
408 RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
411 break;
413 case AL_EXPONENT_DISTANCE_CLAMPED:
414 Distance=__max(Distance,MinDist);
415 Distance=__min(Distance,MaxDist);
416 if(MaxDist < MinDist)
417 break;
418 //fall-through
419 case AL_EXPONENT_DISTANCE:
420 if(Distance > 0.0f && MinDist > 0.0f)
422 Attenuation = aluPow(Distance/MinDist, -Rolloff);
423 for(i = 0;i < NumSends;i++)
424 RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
426 break;
428 case AL_NONE:
429 break;
432 // Source Gain + Attenuation
433 DryGain = SourceVolume * Attenuation;
434 for(i = 0;i < NumSends;i++)
435 WetGain[i] = SourceVolume * RoomAttenuation[i];
437 EffectiveDist = 0.0f;
438 if(MinDist > 0.0f && Attenuation < 1.0f)
439 EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
441 // Distance-based air absorption
442 if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
444 ALfloat absorb;
446 // Absorption calculation is done in dB
447 absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
448 EffectiveDist;
449 // Convert dB to linear gain before applying
450 absorb = aluPow(10.0f, absorb/20.0f);
452 DryGainHF *= absorb;
455 //3. Apply directional soundcones
456 Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
457 if(Angle >= InnerAngle && Angle <= OuterAngle)
459 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
460 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
461 ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
463 else if(Angle > OuterAngle)
465 ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
466 ConeHF = (1.0f+(OuterGainHF-1.0f));
468 else
470 ConeVolume = 1.0f;
471 ConeHF = 1.0f;
474 // Apply some high-frequency attenuation for sources behind the listener
475 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
476 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
477 // the same as SourceToListener[2]
478 Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
479 // Sources within the minimum distance attenuate less
480 if(OrigDist < MinDist)
481 Angle *= OrigDist/MinDist;
482 if(Angle > 90.0f)
484 ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
485 ConeHF *= 1.0f - (Device->HeadDampen*scale);
488 DryGain *= ConeVolume;
489 if(ALSource->DryGainHFAuto)
490 DryGainHF *= ConeHF;
492 // Clamp to Min/Max Gain
493 DryGain = __min(DryGain,MaxVolume);
494 DryGain = __max(DryGain,MinVolume);
496 for(i = 0;i < NumSends;i++)
498 ALeffectslot *Slot = ALSource->Send[i].Slot;
500 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
502 ALSource->Params.Send[i].WetGain = 0.0f;
503 WetGainHF[i] = 1.0f;
504 continue;
507 if(Slot->AuxSendAuto)
509 if(ALSource->WetGainAuto)
510 WetGain[i] *= ConeVolume;
511 if(ALSource->WetGainHFAuto)
512 WetGainHF[i] *= ConeHF;
514 // Clamp to Min/Max Gain
515 WetGain[i] = __min(WetGain[i],MaxVolume);
516 WetGain[i] = __max(WetGain[i],MinVolume);
518 if(Slot->effect.type == AL_EFFECT_REVERB ||
519 Slot->effect.type == AL_EFFECT_EAXREVERB)
521 /* Apply a decay-time transformation to the wet path, based on
522 * the attenuation of the dry path.
524 * Using the approximate (effective) source to listener
525 * distance, the initial decay of the reverb effect is
526 * calculated and applied to the wet path.
528 WetGain[i] *= aluPow(10.0f, EffectiveDist /
529 (SPEEDOFSOUNDMETRESPERSEC *
530 Slot->effect.Reverb.DecayTime) *
531 -60.0 / 20.0);
533 WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
534 AirAbsorptionFactor * EffectiveDist);
537 else
539 /* If the slot's auxiliary send auto is off, the data sent to the
540 * effect slot is the same as the dry path, sans filter effects */
541 WetGain[i] = DryGain;
542 WetGainHF[i] = DryGainHF;
545 switch(ALSource->Send[i].WetFilter.type)
547 case AL_FILTER_LOWPASS:
548 WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
549 WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
550 break;
552 ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
555 // Apply filter gains and filters
556 switch(ALSource->DirectFilter.type)
558 case AL_FILTER_LOWPASS:
559 DryGain *= ALSource->DirectFilter.Gain;
560 DryGainHF *= ALSource->DirectFilter.GainHF;
561 break;
563 DryGain *= ListenerGain;
565 // Calculate Velocity
566 Pitch = ALSource->flPitch;
567 if(DopplerFactor != 0.0f)
569 ALfloat VSS, VLS;
570 ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
571 DopplerFactor;
573 VSS = aluDotproduct(Velocity, SourceToListener);
574 if(VSS >= MaxVelocity)
575 VSS = (MaxVelocity - 1.0f);
576 else if(VSS <= -MaxVelocity)
577 VSS = -MaxVelocity + 1.0f;
579 VLS = aluDotproduct(ListenerVel, SourceToListener);
580 if(VLS >= MaxVelocity)
581 VLS = (MaxVelocity - 1.0f);
582 else if(VLS <= -MaxVelocity)
583 VLS = -MaxVelocity + 1.0f;
585 Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
586 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
589 BufferListItem = ALSource->queue;
590 while(BufferListItem != NULL)
592 ALbuffer *ALBuffer;
593 if((ALBuffer=BufferListItem->buffer) != NULL)
595 ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtType,
596 ALBuffer->FmtChannels);
597 maxstep -= ResamplerPadding[ALSource->Resampler] +
598 ResamplerPrePadding[ALSource->Resampler] + 1;
599 maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
601 Pitch = Pitch * ALBuffer->frequency / Frequency;
602 if(Pitch > (ALfloat)maxstep)
603 ALSource->Params.Step = maxstep<<FRACTIONBITS;
604 else
606 ALSource->Params.Step = Pitch*FRACTIONONE;
607 if(ALSource->Params.Step == 0)
608 ALSource->Params.Step = 1;
610 break;
612 BufferListItem = BufferListItem->next;
615 // Use energy-preserving panning algorithm for multi-speaker playback
616 length = __max(OrigDist, MinDist);
617 if(length > 0.0f)
619 ALfloat invlen = 1.0f/length;
620 Position[0] *= invlen;
621 Position[1] *= invlen;
622 Position[2] *= invlen;
625 pos = aluCart2LUTpos(-Position[2], Position[0]);
626 SpeakerGain = &Device->PanningLUT[OUTPUTCHANNELS * pos];
628 DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
629 // elevation adjustment for directional gain. this sucks, but
630 // has low complexity
631 AmbientGain = aluSqrt(1.0/Device->NumChan);
632 for(s = 0;s < OUTPUTCHANNELS;s++)
633 ALSource->Params.DryGains[s] = 0.0f;
634 for(s = 0;s < (ALsizei)Device->NumChan;s++)
636 Channel chan = Device->Speaker2Chan[s];
637 ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
638 ALSource->Params.DryGains[chan] = DryGain * gain;
641 /* Update filter coefficients. */
642 cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
644 /* Spatialized sources use four chained one-pole filters, so we need to
645 * take the fourth root of the squared gain, which is the same as the
646 * square root of the base gain. */
647 ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
649 for(i = 0;i < NumSends;i++)
651 /* The wet path uses two chained one-pole filters, so take the
652 * base gain (square root of the squared gain) */
653 ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
658 static __inline ALfloat aluF2F(ALfloat Value)
660 return Value;
662 static __inline ALshort aluF2S(ALfloat Value)
664 ALint i;
666 if(Value <= -1.0f) i = -32768;
667 else if(Value >= 1.0f) i = 32767;
668 else i = (ALint)(Value*32767.0f);
670 return ((ALshort)i);
672 static __inline ALubyte aluF2UB(ALfloat Value)
674 ALshort i = aluF2S(Value);
675 return (i>>8)+128;
678 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
680 ALuint SamplesToDo;
681 ALeffectslot *ALEffectSlot;
682 ALCcontext **ctx, **ctx_end;
683 ALsource **src, **src_end;
684 int fpuState;
685 ALuint i, j, c;
686 ALsizei e;
688 #if defined(HAVE_FESETROUND)
689 fpuState = fegetround();
690 fesetround(FE_TOWARDZERO);
691 #elif defined(HAVE__CONTROLFP)
692 fpuState = _controlfp(_RC_CHOP, _MCW_RC);
693 #else
694 (void)fpuState;
695 #endif
697 while(size > 0)
699 /* Setup variables */
700 SamplesToDo = min(size, BUFFERSIZE);
702 /* Clear mixing buffer */
703 memset(device->DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
705 SuspendContext(NULL);
706 ctx = device->Contexts;
707 ctx_end = ctx + device->NumContexts;
708 while(ctx != ctx_end)
710 SuspendContext(*ctx);
712 src = (*ctx)->ActiveSources;
713 src_end = src + (*ctx)->ActiveSourceCount;
714 while(src != src_end)
716 if((*src)->state != AL_PLAYING)
718 --((*ctx)->ActiveSourceCount);
719 *src = *(--src_end);
720 continue;
723 if((*src)->NeedsUpdate)
725 ALsource_Update(*src, *ctx);
726 (*src)->NeedsUpdate = AL_FALSE;
729 MixSource(*src, device, SamplesToDo);
730 src++;
733 /* effect slot processing */
734 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
736 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
738 for(i = 0;i < SamplesToDo;i++)
740 ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
741 ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
743 for(i = 0;i < 1;i++)
745 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
746 ALEffectSlot->PendingClicks[i] = 0.0f;
749 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
750 SamplesToDo, ALEffectSlot->WetBuffer,
751 device->DryBuffer);
753 for(i = 0;i < SamplesToDo;i++)
754 ALEffectSlot->WetBuffer[i] = 0.0f;
757 ProcessContext(*ctx);
758 ctx++;
760 ProcessContext(NULL);
762 //Post processing loop
763 for(i = 0;i < SamplesToDo;i++)
765 for(c = 0;c < OUTPUTCHANNELS;c++)
767 device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
768 device->DryBuffer[i][c] += device->ClickRemoval[c];
771 for(i = 0;i < OUTPUTCHANNELS;i++)
773 device->ClickRemoval[i] += device->PendingClicks[i];
774 device->PendingClicks[i] = 0.0f;
777 switch(device->Format)
779 #define DO_WRITE(T, func, N, ...) do { \
780 const Channel chans[] = { \
781 __VA_ARGS__ \
782 }; \
783 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
784 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
785 const ALuint *ChanMap = device->DevChannels; \
787 for(i = 0;i < SamplesToDo;i++) \
789 for(j = 0;j < N;j++) \
791 ALfloat samp = 0.0f; \
792 for(c = 0;c < OUTPUTCHANNELS;c++) \
793 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
794 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
796 buffer = ((T*)buffer) + N; \
798 } while(0)
800 #define CHECK_WRITE_FORMAT(bits, T, func) \
801 case AL_FORMAT_MONO##bits: \
802 DO_WRITE(T, func, 1, FRONT_CENTER); \
803 break; \
804 case AL_FORMAT_STEREO##bits: \
805 if(device->Bs2b) \
807 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
808 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
809 const ALuint *ChanMap = device->DevChannels; \
811 for(i = 0;i < SamplesToDo;i++) \
813 float samples[2] = { 0.0f, 0.0f }; \
814 for(c = 0;c < OUTPUTCHANNELS;c++) \
816 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
817 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
819 bs2b_cross_feed(device->Bs2b, samples); \
820 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
821 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
822 buffer = ((T*)buffer) + 2; \
825 else \
826 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
827 break; \
828 case AL_FORMAT_QUAD##bits: \
829 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
830 BACK_LEFT, BACK_RIGHT); \
831 break; \
832 case AL_FORMAT_51CHN##bits: \
833 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
834 FRONT_CENTER, LFE, \
835 BACK_LEFT, BACK_RIGHT); \
836 break; \
837 case AL_FORMAT_61CHN##bits: \
838 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
839 FRONT_CENTER, LFE, BACK_CENTER, \
840 SIDE_LEFT, SIDE_RIGHT); \
841 break; \
842 case AL_FORMAT_71CHN##bits: \
843 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
844 FRONT_CENTER, LFE, \
845 BACK_LEFT, BACK_RIGHT, \
846 SIDE_LEFT, SIDE_RIGHT); \
847 break;
849 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
850 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
851 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
852 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
853 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
854 #undef AL_FORMAT_STEREO32
855 #undef AL_FORMAT_MONO32
856 #undef CHECK_WRITE_FORMAT
857 #undef DO_WRITE
859 default:
860 break;
863 size -= SamplesToDo;
866 #if defined(HAVE_FESETROUND)
867 fesetround(fpuState);
868 #elif defined(HAVE__CONTROLFP)
869 _controlfp(fpuState, _MCW_RC);
870 #endif
874 ALvoid aluHandleDisconnect(ALCdevice *device)
876 ALuint i;
878 SuspendContext(NULL);
879 for(i = 0;i < device->NumContexts;i++)
881 ALCcontext *Context = device->Contexts[i];
882 ALsource *source;
883 ALsizei pos;
885 SuspendContext(Context);
887 for(pos = 0;pos < Context->SourceMap.size;pos++)
889 source = Context->SourceMap.array[pos].value;
890 if(source->state == AL_PLAYING)
892 source->state = AL_STOPPED;
893 source->BuffersPlayed = source->BuffersInQueue;
894 source->position = 0;
895 source->position_fraction = 0;
898 ProcessContext(Context);
901 device->Connected = ALC_FALSE;
902 ProcessContext(NULL);