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 #define _CRT_SECURE_NO_DEPRECATE // get rid of sprintf security warnings on VS2005
32 #include "alListener.h"
34 #if defined(HAVE_STDINT_H)
36 typedef int64_t ALint64
;
37 #elif defined(HAVE___INT64)
38 typedef __int64 ALint64
;
39 #elif (SIZEOF_LONG == 8)
41 #elif (SIZEOF_LONG_LONG == 8)
42 typedef long long ALint64
;
46 #define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
48 #define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
52 #if defined(max) && !defined(__max)
55 #if defined(min) && !defined(__min)
59 #define BUFFERSIZE 48000
60 #define FRACTIONBITS 14
61 #define FRACTIONMASK ((1L<<FRACTIONBITS)-1)
77 /* NOTE: The AL_FORMAT_REAR* enums aren't handled here be cause they're
78 * converted to AL_FORMAT_QUAD* when loaded */
79 __inline ALuint
aluBytesFromFormat(ALenum format
)
84 case AL_FORMAT_STEREO8
:
86 case AL_FORMAT_51CHN8
:
87 case AL_FORMAT_61CHN8
:
88 case AL_FORMAT_71CHN8
:
91 case AL_FORMAT_MONO16
:
92 case AL_FORMAT_STEREO16
:
93 case AL_FORMAT_QUAD16
:
94 case AL_FORMAT_51CHN16
:
95 case AL_FORMAT_61CHN16
:
96 case AL_FORMAT_71CHN16
:
99 case AL_FORMAT_MONO_FLOAT32
:
100 case AL_FORMAT_STEREO_FLOAT32
:
101 case AL_FORMAT_QUAD32
:
102 case AL_FORMAT_51CHN32
:
103 case AL_FORMAT_61CHN32
:
104 case AL_FORMAT_71CHN32
:
112 __inline ALuint
aluChannelsFromFormat(ALenum format
)
116 case AL_FORMAT_MONO8
:
117 case AL_FORMAT_MONO16
:
118 case AL_FORMAT_MONO_FLOAT32
:
121 case AL_FORMAT_STEREO8
:
122 case AL_FORMAT_STEREO16
:
123 case AL_FORMAT_STEREO_FLOAT32
:
126 case AL_FORMAT_QUAD8
:
127 case AL_FORMAT_QUAD16
:
128 case AL_FORMAT_QUAD32
:
131 case AL_FORMAT_51CHN8
:
132 case AL_FORMAT_51CHN16
:
133 case AL_FORMAT_51CHN32
:
136 case AL_FORMAT_61CHN8
:
137 case AL_FORMAT_61CHN16
:
138 case AL_FORMAT_61CHN32
:
141 case AL_FORMAT_71CHN8
:
142 case AL_FORMAT_71CHN16
:
143 case AL_FORMAT_71CHN32
:
151 static __inline ALint
aluF2L(ALfloat Value
)
153 if(sizeof(ALint
) == 4 && sizeof(double) == 8)
156 temp
= Value
+ (((65536.0*65536.0*16.0)+(65536.0*65536.0*8.0))*65536.0);
157 return *((ALint
*)&temp
);
162 static __inline ALshort
aluF2S(ALfloat Value
)
167 i
= __min( 32767, i
);
168 i
= __max(-32768, i
);
172 static __inline ALvoid
aluCrossproduct(ALfloat
*inVector1
,ALfloat
*inVector2
,ALfloat
*outVector
)
174 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
175 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
176 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
179 static __inline ALfloat
aluDotproduct(ALfloat
*inVector1
,ALfloat
*inVector2
)
181 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
182 inVector1
[2]*inVector2
[2];
185 static __inline ALvoid
aluNormalize(ALfloat
*inVector
)
187 ALfloat length
, inverse_length
;
189 length
= (ALfloat
)aluSqrt(aluDotproduct(inVector
, inVector
));
192 inverse_length
= 1.0f
/length
;
193 inVector
[0] *= inverse_length
;
194 inVector
[1] *= inverse_length
;
195 inVector
[2] *= inverse_length
;
199 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat matrix
[3][3])
203 result
[0] = vector
[0]*matrix
[0][0] + vector
[1]*matrix
[1][0] + vector
[2]*matrix
[2][0];
204 result
[1] = vector
[0]*matrix
[0][1] + vector
[1]*matrix
[1][1] + vector
[2]*matrix
[2][1];
205 result
[2] = vector
[0]*matrix
[0][2] + vector
[1]*matrix
[1][2] + vector
[2]*matrix
[2][2];
206 memcpy(vector
, result
, sizeof(result
));
209 static __inline ALfloat
aluComputeDrySample(ALsource
*source
, ALfloat DryGainHF
, ALfloat sample
)
214 sample
+= source
->LastDrySample
* (1.0f
- DryGainHF
);
217 source
->LastDrySample
= sample
;
221 static __inline ALfloat
aluComputeWetSample(ALsource
*source
, ALfloat WetGainHF
, ALfloat sample
)
226 sample
+= source
->LastWetSample
* (1.0f
- WetGainHF
);
229 source
->LastWetSample
= sample
;
233 static ALvoid
CalcSourceParams(ALCcontext
*ALContext
, ALsource
*ALSource
,
234 ALenum isMono
, ALenum OutputFormat
,
235 ALfloat
*drysend
, ALfloat
*wetsend
,
236 ALfloat
*pitch
, ALfloat
*drygainhf
,
239 ALfloat ListenerOrientation
[6],ListenerPosition
[3],ListenerVelocity
[3];
240 ALfloat InnerAngle
,OuterAngle
,OuterGain
,Angle
,Distance
,DryMix
,WetMix
;
241 ALfloat Direction
[3],Position
[3],Velocity
[3],SourceToListener
[3];
242 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
,OuterGainHF
;
243 ALfloat Pitch
,ConeVolume
,SourceVolume
,PanningFB
,PanningLR
,ListenerGain
;
244 ALfloat U
[3],V
[3],N
[3];
245 ALfloat DopplerFactor
, DopplerVelocity
, flSpeedOfSound
, flMaxVelocity
;
246 ALfloat flVSS
, flVLS
;
248 ALfloat Matrix
[3][3];
250 ALfloat flAttenuation
;
251 ALfloat RoomAttenuation
;
252 ALfloat MetersPerUnit
;
254 ALfloat DryGainHF
= 1.0f
;
255 ALfloat WetGainHF
= 1.0f
;
257 //Get context properties
258 DopplerFactor
= ALContext
->DopplerFactor
;
259 DistanceModel
= ALContext
->DistanceModel
;
260 DopplerVelocity
= ALContext
->DopplerVelocity
;
261 flSpeedOfSound
= ALContext
->flSpeedOfSound
;
263 //Get listener properties
264 ListenerGain
= ALContext
->Listener
.Gain
;
265 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
266 memcpy(ListenerPosition
, ALContext
->Listener
.Position
, sizeof(ALContext
->Listener
.Position
));
267 memcpy(ListenerVelocity
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
268 memcpy(&ListenerOrientation
[0], ALContext
->Listener
.Forward
, sizeof(ALContext
->Listener
.Forward
));
269 memcpy(&ListenerOrientation
[3], ALContext
->Listener
.Up
, sizeof(ALContext
->Listener
.Up
));
271 //Get source properties
272 Pitch
= ALSource
->flPitch
;
273 SourceVolume
= ALSource
->flGain
;
274 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
275 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
276 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
277 MinVolume
= ALSource
->flMinGain
;
278 MaxVolume
= ALSource
->flMaxGain
;
279 MinDist
= ALSource
->flRefDistance
;
280 MaxDist
= ALSource
->flMaxDistance
;
281 Rolloff
= ALSource
->flRollOffFactor
;
282 OuterGain
= ALSource
->flOuterGain
;
283 InnerAngle
= ALSource
->flInnerAngle
;
284 OuterAngle
= ALSource
->flOuterAngle
;
285 HeadRelative
= ALSource
->bHeadRelative
;
286 OuterGainHF
= ALSource
->OuterGainHF
;
287 RoomRolloff
= ALSource
->RoomRolloffFactor
;
289 //Only apply 3D calculations for mono buffers
290 if(isMono
!= AL_FALSE
)
292 //1. Translate Listener to origin (convert to head relative)
293 if(HeadRelative
==AL_FALSE
)
295 Position
[0] -= ListenerPosition
[0];
296 Position
[1] -= ListenerPosition
[1];
297 Position
[2] -= ListenerPosition
[2];
300 //2. Calculate distance attenuation
301 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
303 flAttenuation
= 1.0f
;
304 RoomAttenuation
= 1.0f
;
305 switch (DistanceModel
)
307 case AL_INVERSE_DISTANCE_CLAMPED
:
308 Distance
=__max(Distance
,MinDist
);
309 Distance
=__min(Distance
,MaxDist
);
310 if (MaxDist
< MinDist
)
313 case AL_INVERSE_DISTANCE
:
316 if ((MinDist
+ (Rolloff
* (Distance
- MinDist
))) > 0.0f
)
317 flAttenuation
= MinDist
/ (MinDist
+ (Rolloff
* (Distance
- MinDist
)));
318 if ((MinDist
+ (RoomRolloff
* (Distance
- MinDist
))) > 0.0f
)
319 RoomAttenuation
= MinDist
/ (MinDist
+ (RoomRolloff
* (Distance
- MinDist
)));
323 case AL_LINEAR_DISTANCE_CLAMPED
:
324 Distance
=__max(Distance
,MinDist
);
325 Distance
=__min(Distance
,MaxDist
);
326 if (MaxDist
< MinDist
)
329 case AL_LINEAR_DISTANCE
:
330 Distance
=__min(Distance
,MaxDist
);
331 if (MaxDist
!= MinDist
)
333 flAttenuation
= 1.0f
- (Rolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
334 RoomAttenuation
= 1.0f
- (RoomRolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
338 case AL_EXPONENT_DISTANCE_CLAMPED
:
339 Distance
=__max(Distance
,MinDist
);
340 Distance
=__min(Distance
,MaxDist
);
341 if (MaxDist
< MinDist
)
344 case AL_EXPONENT_DISTANCE
:
345 if ((Distance
> 0.0f
) && (MinDist
> 0.0f
))
347 flAttenuation
= (ALfloat
)pow(Distance
/MinDist
, -Rolloff
);
348 RoomAttenuation
= (ALfloat
)pow(Distance
/MinDist
, -RoomRolloff
);
354 flAttenuation
= 1.0f
;
355 RoomAttenuation
= 1.0f
;
359 // Source Gain + Attenuation
360 DryMix
= SourceVolume
* flAttenuation
;
361 WetMix
= SourceVolume
* ((ALSource
->WetGainAuto
&&
362 ALSource
->Send
[0].Slot
.AuxSendAuto
) ?
363 RoomAttenuation
: 1.0f
);
365 // Clamp to Min/Max Gain
366 DryMix
= __min(DryMix
,MaxVolume
);
367 DryMix
= __max(DryMix
,MinVolume
);
368 WetMix
= __min(WetMix
,MaxVolume
);
369 WetMix
= __max(WetMix
,MinVolume
);
370 //3. Apply directional soundcones
371 SourceToListener
[0] = -Position
[0];
372 SourceToListener
[1] = -Position
[1];
373 SourceToListener
[2] = -Position
[2];
374 aluNormalize(Direction
);
375 aluNormalize(SourceToListener
);
376 Angle
= (ALfloat
)(180.0*acos(aluDotproduct(Direction
,SourceToListener
))/3.141592654f
);
377 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
379 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
380 ConeVolume
= (1.0f
+(OuterGain
-1.0f
)*scale
);
381 if(ALSource
->WetGainAuto
)
382 WetMix
*= ConeVolume
;
383 if(ALSource
->DryGainHFAuto
)
384 DryGainHF
*= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
385 if(ALSource
->WetGainHFAuto
)
386 WetGainHF
*= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
388 else if(Angle
> OuterAngle
)
390 ConeVolume
= (1.0f
+(OuterGain
-1.0f
));
391 if(ALSource
->WetGainAuto
)
392 WetMix
*= ConeVolume
;
393 if(ALSource
->DryGainHFAuto
)
394 DryGainHF
*= (1.0f
+(OuterGainHF
-1.0f
));
395 if(ALSource
->WetGainHFAuto
)
396 WetGainHF
*= (1.0f
+(OuterGainHF
-1.0f
));
401 //4. Calculate Velocity
402 if(DopplerFactor
!= 0.0f
)
404 flVLS
= aluDotproduct(ListenerVelocity
, SourceToListener
);
405 flVSS
= aluDotproduct(Velocity
, SourceToListener
);
407 flMaxVelocity
= (DopplerVelocity
* flSpeedOfSound
) / DopplerFactor
;
409 if (flVSS
>= flMaxVelocity
)
410 flVSS
= (flMaxVelocity
- 1.0f
);
411 else if (flVSS
<= -flMaxVelocity
)
412 flVSS
= -flMaxVelocity
+ 1.0f
;
414 if (flVLS
>= flMaxVelocity
)
415 flVLS
= (flMaxVelocity
- 1.0f
);
416 else if (flVLS
<= -flMaxVelocity
)
417 flVLS
= -flMaxVelocity
+ 1.0f
;
419 pitch
[0] = Pitch
* ((flSpeedOfSound
* DopplerVelocity
) - (DopplerFactor
* flVLS
)) /
420 ((flSpeedOfSound
* DopplerVelocity
) - (DopplerFactor
* flVSS
));
425 //5. Align coordinate system axes
426 aluCrossproduct(&ListenerOrientation
[0], &ListenerOrientation
[3], U
); // Right-vector
427 aluNormalize(U
); // Normalized Right-vector
428 memcpy(V
, &ListenerOrientation
[3], sizeof(V
)); // Up-vector
429 aluNormalize(V
); // Normalized Up-vector
430 memcpy(N
, &ListenerOrientation
[0], sizeof(N
)); // At-vector
431 aluNormalize(N
); // Normalized At-vector
432 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0];
433 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1];
434 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2];
435 aluMatrixVector(Position
, Matrix
);
437 //6. Apply filter gains and filters
438 switch(ALSource
->DirectFilter
.filter
)
440 case AL_FILTER_LOWPASS
:
441 DryMix
*= ALSource
->DirectFilter
.Gain
;
442 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
446 switch(ALSource
->Send
[0].WetFilter
.filter
)
448 case AL_FILTER_LOWPASS
:
449 WetMix
*= ALSource
->Send
[0].WetFilter
.Gain
;
450 WetGainHF
*= ALSource
->Send
[0].WetFilter
.GainHF
;
454 if(ALSource
->AirAbsorptionFactor
> 0.0f
)
455 DryGainHF
*= pow(ALSource
->AirAbsorptionFactor
* AIRABSORBGAINHF
,
456 Distance
* MetersPerUnit
);
458 *drygainhf
= DryGainHF
;
459 *wetgainhf
= WetGainHF
;
461 //7. Convert normalized position into pannings, then into channel volumes
462 aluNormalize(Position
);
463 WetMix
*= ALSource
->Send
[0].Slot
.Gain
;
464 switch(aluChannelsFromFormat(OutputFormat
))
467 drysend
[FRONT_LEFT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt(1.0f
); //Direct
468 drysend
[FRONT_RIGHT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt(1.0f
); //Direct
469 if(ALSource
->Send
[0].Slot
.effectslot
)
471 wetsend
[FRONT_LEFT
] = ListenerGain
* WetMix
* aluSqrt(1.0f
); //Room
472 wetsend
[FRONT_RIGHT
] = ListenerGain
* WetMix
* aluSqrt(1.0f
); //Room
476 wetsend
[FRONT_LEFT
] = 0.0f
;
477 wetsend
[FRONT_RIGHT
] = 0.0f
;
482 PanningLR
= 0.5f
+ 0.5f
*Position
[0];
483 drysend
[FRONT_LEFT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt(1.0f
-PanningLR
); //L Direct
484 drysend
[FRONT_RIGHT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt( PanningLR
); //R Direct
485 if(ALSource
->Send
[0].Slot
.effectslot
)
487 wetsend
[FRONT_LEFT
] = ListenerGain
* WetMix
* aluSqrt(1.0f
-PanningLR
); //L Room
488 wetsend
[FRONT_RIGHT
] = ListenerGain
* WetMix
* aluSqrt( PanningLR
); //R Room
492 wetsend
[FRONT_LEFT
] = 0.0f
;
493 wetsend
[FRONT_RIGHT
] = 0.0f
;
498 /* TODO: Add center/lfe channel in spatial calculations? */
500 /* TODO: Special paths for 6.1 and 7.1 output would be nice */
503 // Apply a scalar so each individual speaker has more weight
504 PanningLR
= 0.5f
+ (0.5f
*Position
[0]*1.41421356f
);
505 PanningLR
= __min(1.0f
, PanningLR
);
506 PanningLR
= __max(0.0f
, PanningLR
);
507 PanningFB
= 0.5f
+ (0.5f
*Position
[2]*1.41421356f
);
508 PanningFB
= __min(1.0f
, PanningFB
);
509 PanningFB
= __max(0.0f
, PanningFB
);
510 drysend
[FRONT_LEFT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt((1.0f
-PanningLR
)*(1.0f
-PanningFB
)); //FL Direct
511 drysend
[FRONT_RIGHT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt(( PanningLR
)*(1.0f
-PanningFB
)); //FR Direct
512 drysend
[BACK_LEFT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt((1.0f
-PanningLR
)*( PanningFB
)); //BL Direct
513 drysend
[BACK_RIGHT
] = ConeVolume
* ListenerGain
* DryMix
* aluSqrt(( PanningLR
)*( PanningFB
)); //BR Direct
514 drysend
[SIDE_LEFT
] = 0.0f
;
515 drysend
[SIDE_RIGHT
] = 0.0f
;
516 if(ALSource
->Send
[0].Slot
.effectslot
)
518 wetsend
[FRONT_LEFT
] = ListenerGain
* WetMix
* aluSqrt((1.0f
-PanningLR
)*(1.0f
-PanningFB
)); //FL Room
519 wetsend
[FRONT_RIGHT
] = ListenerGain
* WetMix
* aluSqrt(( PanningLR
)*(1.0f
-PanningFB
)); //FR Room
520 wetsend
[BACK_LEFT
] = ListenerGain
* WetMix
* aluSqrt((1.0f
-PanningLR
)*( PanningFB
)); //BL Room
521 wetsend
[BACK_RIGHT
] = ListenerGain
* WetMix
* aluSqrt(( PanningLR
)*( PanningFB
)); //BR Room
525 wetsend
[FRONT_LEFT
] = 0.0f
;
526 wetsend
[FRONT_RIGHT
] = 0.0f
;
527 wetsend
[BACK_LEFT
] = 0.0f
;
528 wetsend
[BACK_RIGHT
] = 0.0f
;
531 wetsend
[SIDE_LEFT
] = 0.0f
;
532 wetsend
[SIDE_RIGHT
] = 0.0f
;
540 *drygainhf
= DryGainHF
;
541 *wetgainhf
= WetGainHF
;
543 //1. Multi-channel buffers always play "normal"
544 drysend
[FRONT_LEFT
] = SourceVolume
* 1.0f
* ListenerGain
;
545 drysend
[FRONT_RIGHT
] = SourceVolume
* 1.0f
* ListenerGain
;
546 drysend
[SIDE_LEFT
] = SourceVolume
* 1.0f
* ListenerGain
;
547 drysend
[SIDE_RIGHT
] = SourceVolume
* 1.0f
* ListenerGain
;
548 drysend
[BACK_LEFT
] = SourceVolume
* 1.0f
* ListenerGain
;
549 drysend
[BACK_RIGHT
] = SourceVolume
* 1.0f
* ListenerGain
;
550 drysend
[CENTER
] = SourceVolume
* 1.0f
* ListenerGain
;
551 drysend
[LFE
] = SourceVolume
* 1.0f
* ListenerGain
;
552 if(ALSource
->Send
[0].Slot
.effectslot
)
554 wetsend
[FRONT_LEFT
] = SourceVolume
* 0.0f
* ListenerGain
;
555 wetsend
[FRONT_RIGHT
] = SourceVolume
* 0.0f
* ListenerGain
;
556 wetsend
[SIDE_LEFT
] = SourceVolume
* 0.0f
* ListenerGain
;
557 wetsend
[SIDE_RIGHT
] = SourceVolume
* 0.0f
* ListenerGain
;
558 wetsend
[BACK_LEFT
] = SourceVolume
* 0.0f
* ListenerGain
;
559 wetsend
[BACK_RIGHT
] = SourceVolume
* 0.0f
* ListenerGain
;
560 wetsend
[CENTER
] = SourceVolume
* 0.0f
* ListenerGain
;
561 wetsend
[LFE
] = SourceVolume
* 0.0f
* ListenerGain
;
569 ALvoid
aluMixData(ALCcontext
*ALContext
,ALvoid
*buffer
,ALsizei size
,ALenum format
)
571 static float DryBuffer
[BUFFERSIZE
][OUTPUTCHANNELS
];
572 static float WetBuffer
[BUFFERSIZE
][OUTPUTCHANNELS
];
573 ALfloat DrySend
[OUTPUTCHANNELS
] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
574 ALfloat WetSend
[OUTPUTCHANNELS
] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
};
575 ALfloat DryGainHF
= 0.0f
;
576 ALfloat WetGainHF
= 0.0f
;
577 ALuint BlockAlign
,BufferSize
;
578 ALuint DataSize
=0,DataPosInt
=0,DataPosFrac
=0;
579 ALuint Channels
,Bits
,Frequency
,ulExtraSamples
;
581 ALint Looping
,increment
,State
;
582 ALuint Buffer
,fraction
;
589 ALbufferlistitem
*BufferListItem
;
591 ALint64 DataSize64
,DataPos64
;
593 SuspendContext(ALContext
);
597 //Figure output format variables
598 BlockAlign
= aluChannelsFromFormat(format
);
599 BlockAlign
*= aluBytesFromFormat(format
);
605 ALSource
= (ALContext
? ALContext
->Source
: NULL
);
606 SamplesToDo
= min(size
, BUFFERSIZE
);
608 //Clear mixing buffer
609 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
610 memset(WetBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
616 State
= ALSource
->state
;
617 while(State
== AL_PLAYING
&& j
< SamplesToDo
)
624 if((Buffer
= ALSource
->ulBufferID
))
626 ALBuffer
= (ALbuffer
*)ALTHUNK_LOOKUPENTRY(Buffer
);
628 Data
= ALBuffer
->data
;
629 Bits
= aluBytesFromFormat(ALBuffer
->format
) * 8;
630 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
631 DataSize
= ALBuffer
->size
;
632 Frequency
= ALBuffer
->frequency
;
634 CalcSourceParams(ALContext
, ALSource
,
635 (Channels
==1) ? AL_TRUE
: AL_FALSE
,
636 format
, DrySend
, WetSend
, &Pitch
,
637 &DryGainHF
, &WetGainHF
);
640 Pitch
= (Pitch
*Frequency
) / ALContext
->Frequency
;
641 DataSize
= DataSize
/ (Bits
*Channels
/8);
644 DataPosInt
= ALSource
->position
;
645 DataPosFrac
= ALSource
->position_fraction
;
647 //Compute 18.14 fixed point step
648 increment
= aluF2L(Pitch
*(1L<<FRACTIONBITS
));
649 if(increment
> (MAX_PITCH
<<FRACTIONBITS
))
650 increment
= (MAX_PITCH
<<FRACTIONBITS
);
652 //Figure out how many samples we can mix.
653 //Pitch must be <= 4 (the number below !)
654 DataSize64
= DataSize
+MAX_PITCH
;
655 DataSize64
<<= FRACTIONBITS
;
656 DataPos64
= DataPosInt
;
657 DataPos64
<<= FRACTIONBITS
;
658 DataPos64
+= DataPosFrac
;
659 BufferSize
= (ALuint
)((DataSize64
-DataPos64
) / increment
);
660 BufferListItem
= ALSource
->queue
;
661 for(loop
= 0; loop
< ALSource
->BuffersPlayed
; loop
++)
664 BufferListItem
= BufferListItem
->next
;
668 if (BufferListItem
->next
)
670 if(BufferListItem
->next
->buffer
&&
671 ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(BufferListItem
->next
->buffer
))->data
)
673 ulExtraSamples
= min(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(BufferListItem
->next
->buffer
))->size
, (ALint
)(16*Channels
));
674 memcpy(&Data
[DataSize
*Channels
], ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(BufferListItem
->next
->buffer
))->data
, ulExtraSamples
);
677 else if (ALSource
->bLooping
)
679 if (ALSource
->queue
->buffer
)
681 if(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALSource
->queue
->buffer
))->data
)
683 ulExtraSamples
= min(((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALSource
->queue
->buffer
))->size
, (ALint
)(16*Channels
));
684 memcpy(&Data
[DataSize
*Channels
], ((ALbuffer
*)ALTHUNK_LOOKUPENTRY(ALSource
->queue
->buffer
))->data
, ulExtraSamples
);
689 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
691 //Actual sample mixing loop
692 Data
+= DataPosInt
*Channels
;
695 k
= DataPosFrac
>>FRACTIONBITS
;
696 fraction
= DataPosFrac
&FRACTIONMASK
;
699 //First order interpolator
700 ALfloat sample
= (ALfloat
)((ALshort
)(((Data
[k
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[k
+1]*(fraction
)))>>FRACTIONBITS
));
702 //Direct path final mix buffer and panning
703 value
= aluComputeDrySample(ALSource
, DryGainHF
, sample
);
704 DryBuffer
[j
][FRONT_LEFT
] += value
*DrySend
[FRONT_LEFT
];
705 DryBuffer
[j
][FRONT_RIGHT
] += value
*DrySend
[FRONT_RIGHT
];
706 #if 0 /* FIXME: Re-enable when proper 6-channel spatialization is used */
707 DryBuffer
[j
][SIDE_LEFT
] += value
*DrySend
[SIDE_LEFT
];
708 DryBuffer
[j
][SIDE_RIGHT
] += value
*DrySend
[SIDE_RIGHT
];
710 DryBuffer
[j
][BACK_LEFT
] += value
*DrySend
[BACK_LEFT
];
711 DryBuffer
[j
][BACK_RIGHT
] += value
*DrySend
[BACK_RIGHT
];
712 //Room path final mix buffer and panning
713 value
= aluComputeWetSample(ALSource
, WetGainHF
, sample
);
714 WetBuffer
[j
][FRONT_LEFT
] += value
*WetSend
[FRONT_LEFT
];
715 WetBuffer
[j
][FRONT_RIGHT
] += value
*WetSend
[FRONT_RIGHT
];
716 #if 0 /* FIXME: Re-enable when proper 6-channel spatialization is used */
717 WetBuffer
[j
][SIDE_LEFT
] += value
*WetSend
[SIDE_LEFT
];
718 WetBuffer
[j
][SIDE_RIGHT
] += value
*WetSend
[SIDE_RIGHT
];
720 WetBuffer
[j
][BACK_LEFT
] += value
*WetSend
[BACK_LEFT
];
721 WetBuffer
[j
][BACK_RIGHT
] += value
*WetSend
[BACK_RIGHT
];
725 //First order interpolator (front left)
726 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
]*(fraction
)))>>FRACTIONBITS
));
727 DryBuffer
[j
][FRONT_LEFT
] += value
*DrySend
[FRONT_LEFT
];
728 WetBuffer
[j
][FRONT_LEFT
] += value
*WetSend
[FRONT_LEFT
];
729 //First order interpolator (front right)
730 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+1]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+1]*(fraction
)))>>FRACTIONBITS
));
731 DryBuffer
[j
][FRONT_RIGHT
] += value
*DrySend
[FRONT_RIGHT
];
732 WetBuffer
[j
][FRONT_RIGHT
] += value
*WetSend
[FRONT_RIGHT
];
738 //First order interpolator (side left)
739 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+2]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+2]*(fraction
)))>>FRACTIONBITS
));
740 DryBuffer
[j
][SIDE_LEFT
] += value
*DrySend
[SIDE_LEFT
];
741 WetBuffer
[j
][SIDE_LEFT
] += value
*WetSend
[SIDE_LEFT
];
742 //First order interpolator (side right)
743 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+3]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+3]*(fraction
)))>>FRACTIONBITS
));
744 DryBuffer
[j
][SIDE_RIGHT
] += value
*DrySend
[SIDE_RIGHT
];
745 WetBuffer
[j
][SIDE_RIGHT
] += value
*WetSend
[SIDE_RIGHT
];
748 //First order interpolator (back left)
749 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+i
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+i
]*(fraction
)))>>FRACTIONBITS
));
750 DryBuffer
[j
][BACK_LEFT
] += value
*DrySend
[BACK_LEFT
];
751 WetBuffer
[j
][BACK_LEFT
] += value
*WetSend
[BACK_LEFT
];
753 //First order interpolator (back right)
754 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+i
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+i
]*(fraction
)))>>FRACTIONBITS
));
755 DryBuffer
[j
][BACK_RIGHT
] += value
*DrySend
[BACK_RIGHT
];
756 WetBuffer
[j
][BACK_RIGHT
] += value
*WetSend
[BACK_RIGHT
];
762 //First order interpolator (center)
763 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+i
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+i
]*(fraction
)))>>FRACTIONBITS
));
764 DryBuffer
[j
][CENTER
] += value
*DrySend
[CENTER
];
765 WetBuffer
[j
][CENTER
] += value
*WetSend
[CENTER
];
768 //First order interpolator (lfe)
769 value
= (ALfloat
)((ALshort
)(((Data
[k
*Channels
+i
]*((1L<<FRACTIONBITS
)-fraction
))+(Data
[(k
+1)*Channels
+i
]*(fraction
)))>>FRACTIONBITS
));
770 DryBuffer
[j
][LFE
] += value
*DrySend
[LFE
];
771 WetBuffer
[j
][LFE
] += value
*WetSend
[LFE
];
775 DataPosFrac
+= increment
;
778 DataPosInt
+= (DataPosFrac
>>FRACTIONBITS
);
779 DataPosFrac
= (DataPosFrac
&FRACTIONMASK
);
782 ALSource
->position
= DataPosInt
;
783 ALSource
->position_fraction
= DataPosFrac
;
786 //Handle looping sources
787 if(!Buffer
|| DataPosInt
>= DataSize
)
792 Looping
= ALSource
->bLooping
;
793 if(ALSource
->BuffersPlayed
< (ALSource
->BuffersInQueue
-1))
795 BufferListItem
= ALSource
->queue
;
796 for(loop
= 0; loop
<= ALSource
->BuffersPlayed
; loop
++)
801 BufferListItem
->bufferstate
= PROCESSED
;
802 BufferListItem
= BufferListItem
->next
;
806 ALSource
->BuffersProcessed
++;
808 ALSource
->ulBufferID
= BufferListItem
->buffer
;
809 ALSource
->position
= DataPosInt
-DataSize
;
810 ALSource
->position_fraction
= DataPosFrac
;
811 ALSource
->BuffersPlayed
++;
818 ALSource
->state
= AL_STOPPED
;
819 ALSource
->inuse
= AL_FALSE
;
820 ALSource
->BuffersPlayed
= ALSource
->BuffersProcessed
= ALSource
->BuffersInQueue
;
821 BufferListItem
= ALSource
->queue
;
822 while(BufferListItem
!= NULL
)
824 BufferListItem
->bufferstate
= PROCESSED
;
825 BufferListItem
= BufferListItem
->next
;
832 ALSource
->state
= AL_PLAYING
;
833 ALSource
->inuse
= AL_TRUE
;
834 ALSource
->play
= AL_TRUE
;
835 ALSource
->BuffersPlayed
= 0;
836 ALSource
->BufferPosition
= 0;
837 ALSource
->lBytesPlayed
= 0;
838 ALSource
->BuffersProcessed
= 0;
839 BufferListItem
= ALSource
->queue
;
840 while(BufferListItem
!= NULL
)
842 BufferListItem
->bufferstate
= PENDING
;
843 BufferListItem
= BufferListItem
->next
;
845 ALSource
->ulBufferID
= ALSource
->queue
->buffer
;
847 ALSource
->position
= DataPosInt
-DataSize
;
848 ALSource
->position_fraction
= DataPosFrac
;
855 State
= ALSource
->state
;
858 ALSource
= ALSource
->next
;
861 //Post processing loop
864 case AL_FORMAT_MONO8
:
865 for(i
= 0;i
< SamplesToDo
;i
++)
867 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
]+DryBuffer
[i
][FRONT_RIGHT
]+
868 WetBuffer
[i
][FRONT_LEFT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
869 buffer
= ((ALubyte
*)buffer
) + 1;
872 case AL_FORMAT_STEREO8
:
873 for(i
= 0;i
< SamplesToDo
;i
++)
875 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
])>>8)+128);
876 ((ALubyte
*)buffer
)[1] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
877 buffer
= ((ALubyte
*)buffer
) + 2;
880 case AL_FORMAT_QUAD8
:
881 for(i
= 0;i
< SamplesToDo
;i
++)
883 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
])>>8)+128);
884 ((ALubyte
*)buffer
)[1] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
885 ((ALubyte
*)buffer
)[2] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
])>>8)+128);
886 ((ALubyte
*)buffer
)[3] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
])>>8)+128);
887 buffer
= ((ALubyte
*)buffer
) + 4;
890 case AL_FORMAT_51CHN8
:
891 for(i
= 0;i
< SamplesToDo
;i
++)
893 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
])>>8)+128);
894 ((ALubyte
*)buffer
)[1] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
895 ((ALubyte
*)buffer
)[2] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
])>>8)+128);
896 ((ALubyte
*)buffer
)[3] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
])>>8)+128);
897 ((ALubyte
*)buffer
)[4] = (ALubyte
)((aluF2S(DryBuffer
[i
][CENTER
] +WetBuffer
[i
][CENTER
])>>8)+128);
898 ((ALubyte
*)buffer
)[5] = (ALubyte
)((aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
])>>8)+128);
899 buffer
= ((ALubyte
*)buffer
) + 6;
902 case AL_FORMAT_61CHN8
:
903 for(i
= 0;i
< SamplesToDo
;i
++)
905 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
])>>8)+128);
906 ((ALubyte
*)buffer
)[1] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
907 ((ALubyte
*)buffer
)[2] = (ALubyte
)((aluF2S(DryBuffer
[i
][SIDE_LEFT
] +WetBuffer
[i
][SIDE_LEFT
])>>8)+128);
908 ((ALubyte
*)buffer
)[3] = (ALubyte
)((aluF2S(DryBuffer
[i
][SIDE_RIGHT
] +WetBuffer
[i
][SIDE_RIGHT
])>>8)+128);
909 ((ALubyte
*)buffer
)[4] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
])>>8)+128);
910 ((ALubyte
*)buffer
)[5] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
])>>8)+128);
911 ((ALubyte
*)buffer
)[6] = (ALubyte
)((aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
])>>8)+128);
912 buffer
= ((ALubyte
*)buffer
) + 7;
915 case AL_FORMAT_71CHN8
:
916 for(i
= 0;i
< SamplesToDo
;i
++)
918 ((ALubyte
*)buffer
)[0] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
])>>8)+128);
919 ((ALubyte
*)buffer
)[1] = (ALubyte
)((aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
])>>8)+128);
920 ((ALubyte
*)buffer
)[2] = (ALubyte
)((aluF2S(DryBuffer
[i
][SIDE_LEFT
] +WetBuffer
[i
][SIDE_LEFT
])>>8)+128);
921 ((ALubyte
*)buffer
)[3] = (ALubyte
)((aluF2S(DryBuffer
[i
][SIDE_RIGHT
] +WetBuffer
[i
][SIDE_RIGHT
])>>8)+128);
922 ((ALubyte
*)buffer
)[4] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
])>>8)+128);
923 ((ALubyte
*)buffer
)[5] = (ALubyte
)((aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
])>>8)+128);
924 ((ALubyte
*)buffer
)[6] = (ALubyte
)((aluF2S(DryBuffer
[i
][CENTER
] +WetBuffer
[i
][CENTER
])>>8)+128);
925 ((ALubyte
*)buffer
)[7] = (ALubyte
)((aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
])>>8)+128);
926 buffer
= ((ALubyte
*)buffer
) + 8;
930 case AL_FORMAT_MONO16
:
931 for(i
= 0;i
< SamplesToDo
;i
++)
933 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
]+DryBuffer
[i
][FRONT_RIGHT
]+
934 WetBuffer
[i
][FRONT_LEFT
]+WetBuffer
[i
][FRONT_RIGHT
]);
935 buffer
= ((ALshort
*)buffer
) + 1;
938 case AL_FORMAT_STEREO16
:
939 for(i
= 0;i
< SamplesToDo
;i
++)
941 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
]);
942 ((ALshort
*)buffer
)[1] = aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
]);
943 buffer
= ((ALshort
*)buffer
) + 2;
946 case AL_FORMAT_QUAD16
:
947 for(i
= 0;i
< SamplesToDo
;i
++)
949 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
]);
950 ((ALshort
*)buffer
)[1] = aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
]);
951 ((ALshort
*)buffer
)[2] = aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
]);
952 ((ALshort
*)buffer
)[3] = aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
]);
953 buffer
= ((ALshort
*)buffer
) + 4;
956 case AL_FORMAT_51CHN16
:
957 for(i
= 0;i
< SamplesToDo
;i
++)
959 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
]);
960 ((ALshort
*)buffer
)[1] = aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
]);
961 ((ALshort
*)buffer
)[2] = aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
]);
962 ((ALshort
*)buffer
)[3] = aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
]);
963 ((ALshort
*)buffer
)[4] = aluF2S(DryBuffer
[i
][CENTER
] +WetBuffer
[i
][CENTER
]);
964 ((ALshort
*)buffer
)[5] = aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
]);
965 buffer
= ((ALshort
*)buffer
) + 6;
968 case AL_FORMAT_61CHN16
:
969 for(i
= 0;i
< SamplesToDo
;i
++)
971 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
]);
972 ((ALshort
*)buffer
)[1] = aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
]);
973 ((ALshort
*)buffer
)[2] = aluF2S(DryBuffer
[i
][SIDE_LEFT
] +WetBuffer
[i
][SIDE_LEFT
]);
974 ((ALshort
*)buffer
)[3] = aluF2S(DryBuffer
[i
][SIDE_RIGHT
] +WetBuffer
[i
][SIDE_RIGHT
]);
975 ((ALshort
*)buffer
)[4] = aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
]);
976 ((ALshort
*)buffer
)[5] = aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
]);
977 ((ALshort
*)buffer
)[6] = aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
]);
978 buffer
= ((ALshort
*)buffer
) + 7;
981 case AL_FORMAT_71CHN16
:
982 for(i
= 0;i
< SamplesToDo
;i
++)
984 ((ALshort
*)buffer
)[0] = aluF2S(DryBuffer
[i
][FRONT_LEFT
] +WetBuffer
[i
][FRONT_LEFT
]);
985 ((ALshort
*)buffer
)[1] = aluF2S(DryBuffer
[i
][FRONT_RIGHT
]+WetBuffer
[i
][FRONT_RIGHT
]);
986 ((ALshort
*)buffer
)[2] = aluF2S(DryBuffer
[i
][SIDE_LEFT
] +WetBuffer
[i
][SIDE_LEFT
]);
987 ((ALshort
*)buffer
)[3] = aluF2S(DryBuffer
[i
][SIDE_RIGHT
] +WetBuffer
[i
][SIDE_RIGHT
]);
988 ((ALshort
*)buffer
)[4] = aluF2S(DryBuffer
[i
][BACK_LEFT
] +WetBuffer
[i
][BACK_LEFT
]);
989 ((ALshort
*)buffer
)[5] = aluF2S(DryBuffer
[i
][BACK_RIGHT
] +WetBuffer
[i
][BACK_RIGHT
]);
990 ((ALshort
*)buffer
)[6] = aluF2S(DryBuffer
[i
][CENTER
] +WetBuffer
[i
][CENTER
]);
991 ((ALshort
*)buffer
)[7] = aluF2S(DryBuffer
[i
][LFE
] +WetBuffer
[i
][LFE
]);
992 buffer
= ((ALshort
*)buffer
) + 8;
1000 size
-= SamplesToDo
;
1004 ProcessContext(ALContext
);