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
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
40 static __inline ALfloat
aluF2F(ALfloat Value
)
45 static __inline ALshort
aluF2S(ALfloat Value
)
49 if(Value
<= -1.0f
) i
= -32768;
50 else if(Value
>= 1.0f
) i
= 32767;
51 else i
= (ALint
)(Value
*32767.0f
);
56 static __inline ALubyte
aluF2UB(ALfloat Value
)
58 ALshort i
= aluF2S(Value
);
63 static __inline ALfloat
point32(ALfloat val1
, ALfloat val2
, ALint frac
)
69 static __inline ALfloat
lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
71 return val1
+ ((val2
-val1
)*(frac
* (1.0f
/(1<<FRACTIONBITS
))));
73 static __inline ALfloat
cos_lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
75 ALfloat mult
= (1.0f
-cos(frac
* (1.0f
/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5f
;
76 return val1
+ ((val2
-val1
)*mult
);
79 static __inline ALfloat
point16(ALfloat val1
, ALfloat val2
, ALint frac
)
81 return val1
/ 32767.0f
;
85 static __inline ALfloat
lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
87 val1
+= ((val2
-val1
)*(frac
* (1.0f
/(1<<FRACTIONBITS
))));
88 return val1
/ 32767.0f
;
90 static __inline ALfloat
cos_lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
92 ALfloat mult
= (1.0f
-cos(frac
* (1.0f
/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5f
;
93 val1
+= ((val2
-val1
)*mult
);
94 return val1
/ 32767.0f
;
98 #define DO_MIX_MONO(S,sampler) do { \
99 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
100 ALfloat *ClickRemoval, *PendingClicks; \
101 ALuint pos = DataPosInt; \
102 ALuint frac = DataPosFrac; \
103 ALfloat DrySend[OUTPUTCHANNELS]; \
109 DryBuffer = Device->DryBuffer; \
110 ClickRemoval = Device->ClickRemoval; \
111 PendingClicks = Device->PendingClicks; \
112 DryFilter = &Source->Params.iirFilter; \
113 for(i = 0;i < OUTPUTCHANNELS;i++) \
114 DrySend[i] = Source->Params.DryGains[i]; \
118 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
120 value = lpFilter4PC(DryFilter, 0, value); \
121 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
122 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
123 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
124 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
125 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
126 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
127 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
128 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
130 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
132 /* First order interpolator */ \
133 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
135 /* Direct path final mix buffer and panning */ \
136 value = lpFilter4P(DryFilter, 0, value); \
137 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
138 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
139 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
140 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
141 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
142 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
143 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
144 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
147 pos += frac>>FRACTIONBITS; \
148 frac &= FRACTIONMASK; \
151 if(j == SamplesToDo) \
157 ALuint64 pos64 = pos; \
158 pos64 <<= FRACTIONBITS; \
160 pos64 -= increment; \
161 p = pos64>>FRACTIONBITS; \
162 f = pos64&FRACTIONMASK; \
164 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
166 value = lpFilter4PC(DryFilter, 0, value); \
167 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
168 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
169 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
170 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
171 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
172 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
173 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
174 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
177 for(out = 0;out < MAX_SENDS;out++) \
180 ALfloat *WetBuffer; \
181 ALfloat *WetClickRemoval; \
182 ALfloat *WetPendingClicks; \
185 if(!Source->Send[out].Slot || \
186 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
189 WetSend = Source->Params.WetGains[out]; \
190 WetBuffer = Source->Send[out].Slot->WetBuffer; \
191 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
192 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
193 WetFilter = &Source->Params.Send[out].iirFilter; \
196 frac = DataPosFrac; \
201 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
203 value = lpFilter2PC(WetFilter, 0, value); \
204 WetClickRemoval[0] -= value*WetSend; \
206 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
208 /* First order interpolator */ \
209 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
211 /* Room path final mix buffer and panning */ \
212 value = lpFilter2P(WetFilter, 0, value); \
213 WetBuffer[j] += value*WetSend; \
216 pos += frac>>FRACTIONBITS; \
217 frac &= FRACTIONMASK; \
220 if(j == SamplesToDo) \
226 ALuint64 pos64 = pos; \
227 pos64 <<= FRACTIONBITS; \
229 pos64 -= increment; \
230 p = pos64>>FRACTIONBITS; \
231 f = pos64&FRACTIONMASK; \
233 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
235 value = lpFilter2PC(WetFilter, 0, value); \
236 WetPendingClicks[0] += value*WetSend; \
240 DataPosFrac = frac; \
243 #define DO_MIX_STEREO(S,sampler) do { \
244 const ALfloat scaler = 1.0f/Channels; \
245 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
246 ALfloat *ClickRemoval, *PendingClicks; \
247 ALuint pos = DataPosInt; \
248 ALuint frac = DataPosFrac; \
249 ALfloat DrySend[OUTPUTCHANNELS]; \
255 DryBuffer = Device->DryBuffer; \
256 ClickRemoval = Device->ClickRemoval; \
257 PendingClicks = Device->PendingClicks; \
258 DryFilter = &Source->Params.iirFilter; \
259 for(i = 0;i < OUTPUTCHANNELS;i++) \
260 DrySend[i] = Source->Params.DryGains[i]; \
264 for(i = 0;i < Channels;i++) \
266 value = sampler##S(Data.p##S[pos*Channels + i], \
267 Data.p##S[(pos+1)*Channels + i], frac); \
269 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
270 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
271 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
272 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
275 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
277 for(i = 0;i < Channels;i++) \
279 value = sampler##S(Data.p##S[pos*Channels + i], \
280 Data.p##S[(pos+1)*Channels + i], frac); \
282 value = lpFilter2P(DryFilter, chans[i]*2, value); \
283 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
284 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
285 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
289 pos += frac>>FRACTIONBITS; \
290 frac &= FRACTIONMASK; \
293 if(j == SamplesToDo) \
299 ALuint64 pos64 = pos; \
300 pos64 <<= FRACTIONBITS; \
302 pos64 -= increment; \
303 p = pos64>>FRACTIONBITS; \
304 f = pos64&FRACTIONMASK; \
306 for(i = 0;i < Channels;i++) \
308 value = sampler##S(Data.p##S[p*Channels + i], \
309 Data.p##S[(p+1)*Channels + i], f); \
311 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
312 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
313 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
314 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
318 for(out = 0;out < MAX_SENDS;out++) \
321 ALfloat *WetBuffer; \
322 ALfloat *WetClickRemoval; \
323 ALfloat *WetPendingClicks; \
326 if(!Source->Send[out].Slot || \
327 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
330 WetSend = Source->Params.WetGains[out]; \
331 WetBuffer = Source->Send[out].Slot->WetBuffer; \
332 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
333 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
334 WetFilter = &Source->Params.Send[out].iirFilter; \
337 frac = DataPosFrac; \
342 for(i = 0;i < Channels;i++) \
344 value = sampler##S(Data.p##S[pos*Channels + i], \
345 Data.p##S[(pos+1)*Channels + i], frac); \
347 value = lpFilter1PC(WetFilter, chans[i], value); \
348 WetClickRemoval[0] -= value*WetSend * scaler; \
351 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
353 for(i = 0;i < Channels;i++) \
355 value = sampler##S(Data.p##S[pos*Channels + i], \
356 Data.p##S[(pos+1)*Channels + i], frac); \
358 value = lpFilter1P(WetFilter, chans[i], value); \
359 WetBuffer[j] += value*WetSend * scaler; \
363 pos += frac>>FRACTIONBITS; \
364 frac &= FRACTIONMASK; \
367 if(j == SamplesToDo) \
373 ALuint64 pos64 = pos; \
374 pos64 <<= FRACTIONBITS; \
376 pos64 -= increment; \
377 p = pos64>>FRACTIONBITS; \
378 f = pos64&FRACTIONMASK; \
380 for(i = 0;i < Channels;i++) \
382 value = sampler##S(Data.p##S[p*Channels + i], \
383 Data.p##S[(p+1)*Channels + i], f); \
385 value = lpFilter1PC(WetFilter, chans[i], value); \
386 WetPendingClicks[0] += value*WetSend * scaler; \
391 DataPosFrac = frac; \
394 #define DO_MIX_MC(S,sampler) do { \
395 const ALfloat scaler = 1.0f/Channels; \
396 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
397 ALfloat *ClickRemoval, *PendingClicks; \
398 ALuint pos = DataPosInt; \
399 ALuint frac = DataPosFrac; \
400 ALfloat DrySend[OUTPUTCHANNELS]; \
406 DryBuffer = Device->DryBuffer; \
407 ClickRemoval = Device->ClickRemoval; \
408 PendingClicks = Device->PendingClicks; \
409 DryFilter = &Source->Params.iirFilter; \
410 for(i = 0;i < OUTPUTCHANNELS;i++) \
411 DrySend[i] = Source->Params.DryGains[i]; \
415 for(i = 0;i < Channels;i++) \
417 value = sampler##S(Data.p##S[pos*Channels + i], \
418 Data.p##S[(pos+1)*Channels + i], frac); \
420 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
421 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
424 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
426 for(i = 0;i < Channels;i++) \
428 value = sampler##S(Data.p##S[pos*Channels + i], \
429 Data.p##S[(pos+1)*Channels + i], frac); \
431 value = lpFilter2P(DryFilter, chans[i]*2, value); \
432 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
436 pos += frac>>FRACTIONBITS; \
437 frac &= FRACTIONMASK; \
440 if(j == SamplesToDo) \
446 ALuint64 pos64 = pos; \
447 pos64 <<= FRACTIONBITS; \
449 pos64 -= increment; \
450 p = pos64>>FRACTIONBITS; \
451 f = pos64&FRACTIONMASK; \
453 for(i = 0;i < Channels;i++) \
455 value = sampler##S(Data.p##S[p*Channels + i], \
456 Data.p##S[(p+1)*Channels + i], f); \
458 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
459 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
463 for(out = 0;out < MAX_SENDS;out++) \
466 ALfloat *WetBuffer; \
467 ALfloat *WetClickRemoval; \
468 ALfloat *WetPendingClicks; \
471 if(!Source->Send[out].Slot || \
472 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
475 WetSend = Source->Params.WetGains[out]; \
476 WetBuffer = Source->Send[out].Slot->WetBuffer; \
477 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
478 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
479 WetFilter = &Source->Params.Send[out].iirFilter; \
482 frac = DataPosFrac; \
487 for(i = 0;i < Channels;i++) \
489 value = sampler##S(Data.p##S[pos*Channels + i], \
490 Data.p##S[(pos+1)*Channels + i], frac); \
492 value = lpFilter1PC(WetFilter, chans[i], value); \
493 WetClickRemoval[0] -= value*WetSend * scaler; \
496 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
498 for(i = 0;i < Channels;i++) \
500 value = sampler##S(Data.p##S[pos*Channels + i], \
501 Data.p##S[(pos+1)*Channels + i], frac); \
503 value = lpFilter1P(WetFilter, chans[i], value); \
504 WetBuffer[j] += value*WetSend * scaler; \
508 pos += frac>>FRACTIONBITS; \
509 frac &= FRACTIONMASK; \
512 if(j == SamplesToDo) \
518 ALuint64 pos64 = pos; \
519 pos64 <<= FRACTIONBITS; \
521 pos64 -= increment; \
522 p = pos64>>FRACTIONBITS; \
523 f = pos64&FRACTIONMASK; \
525 for(i = 0;i < Channels;i++) \
527 value = sampler##S(Data.p##S[p*Channels + i], \
528 Data.p##S[(p+1)*Channels + i], f); \
530 value = lpFilter1PC(WetFilter, chans[i], value); \
531 WetPendingClicks[0] += value*WetSend * scaler; \
536 DataPosFrac = frac; \
540 #define MIX_MONO(sampler) do { \
542 DO_MIX_MONO(32,sampler); \
543 else if(Bytes == 2) \
544 DO_MIX_MONO(16,sampler); \
547 #define MIX_STEREO(sampler) do { \
548 const int chans[] = { \
549 FRONT_LEFT, FRONT_RIGHT, \
550 SIDE_LEFT, SIDE_RIGHT, \
551 BACK_LEFT, BACK_RIGHT \
555 DO_MIX_STEREO(32,sampler); \
556 else if(Bytes == 2) \
557 DO_MIX_STEREO(16,sampler); \
560 #define MIX_MC(sampler,...) do { \
561 const int chans[] = { __VA_ARGS__ }; \
564 DO_MIX_MC(32,sampler); \
565 else if(Bytes == 2) \
566 DO_MIX_MC(16,sampler); \
570 #define MIX(sampler) do { \
571 if(Channels == 1) /* Mono */ \
573 else if(Channels == 2) /* Stereo */ \
574 MIX_STEREO(sampler); \
575 else if(Channels == 4) /* Quad */ \
576 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
577 BACK_LEFT, BACK_RIGHT); \
578 else if(Channels == 6) /* 5.1 */ \
579 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
581 BACK_LEFT, BACK_RIGHT); \
582 else if(Channels == 7) /* 6.1 */ \
583 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
586 SIDE_LEFT, SIDE_RIGHT); \
587 else if(Channels == 8) /* 7.1 */ \
588 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
590 BACK_LEFT, BACK_RIGHT, \
591 SIDE_LEFT, SIDE_RIGHT); \
595 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
597 ALbufferlistitem
*BufferListItem
;
598 ALint64 DataSize64
,DataPos64
;
600 ALuint DataPosInt
, DataPosFrac
;
601 ALuint BuffersPlayed
;
606 /* Get source info */
607 State
= Source
->state
;
608 BuffersPlayed
= Source
->BuffersPlayed
;
609 DataPosInt
= Source
->position
;
610 DataPosFrac
= Source
->position_fraction
;
611 Looping
= Source
->bLooping
;
613 /* Get current buffer queue item */
614 BufferListItem
= Source
->queue
;
615 for(i
= 0;i
< BuffersPlayed
;i
++)
616 BufferListItem
= BufferListItem
->next
;
620 const ALbuffer
*ALBuffer
;
627 ALuint LoopStart
= 0;
629 ALuint Channels
, Bytes
;
632 /* Get buffer info */
633 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
635 Data
.p8
= ALBuffer
->data
;
636 DataSize
= ALBuffer
->size
;
637 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
638 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
639 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
643 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
645 /* If current pos is beyond the loop range, do not loop */
646 if(DataPosInt
>= LoopEnd
)
650 LoopStart
= ALBuffer
->LoopStart
;
651 LoopEnd
= ALBuffer
->LoopEnd
;
656 if(DataPosInt
>= DataSize
)
659 if(BufferListItem
->next
)
661 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
662 if(NextBuf
&& NextBuf
->size
)
664 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
665 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
666 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
667 NextBuf
->data
, ulExtraSamples
);
672 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
673 if(NextBuf
&& NextBuf
->size
)
675 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
676 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
677 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
678 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
683 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
685 /* Figure out how many samples we can mix. */
686 increment
= Source
->Params
.Step
;
687 DataSize64
= LoopEnd
;
688 DataSize64
<<= FRACTIONBITS
;
689 DataPos64
= DataPosInt
;
690 DataPos64
<<= FRACTIONBITS
;
691 DataPos64
+= DataPosFrac
;
692 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
694 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
696 switch(Source
->Resampler
)
698 case POINT_RESAMPLER
:
700 case LINEAR_RESAMPLER
:
702 case COSINE_RESAMPLER
:
703 MIX(cos_lerp
); break;
710 /* Handle looping sources */
711 if(DataPosInt
>= LoopEnd
)
713 if(BufferListItem
->next
)
715 BufferListItem
= BufferListItem
->next
;
717 DataPosInt
-= DataSize
;
721 BufferListItem
= Source
->queue
;
723 if(Source
->lSourceType
== AL_STATIC
)
724 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
726 DataPosInt
-= DataSize
;
731 BufferListItem
= Source
->queue
;
732 BuffersPlayed
= Source
->BuffersInQueue
;
737 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
739 /* Update source info */
740 Source
->state
= State
;
741 Source
->BuffersPlayed
= BuffersPlayed
;
742 Source
->position
= DataPosInt
;
743 Source
->position_fraction
= DataPosFrac
;
744 Source
->Buffer
= BufferListItem
->buffer
;
748 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
751 ALeffectslot
*ALEffectSlot
;
752 ALCcontext
**ctx
, **ctx_end
;
753 ALsource
**src
, **src_end
;
758 #if defined(HAVE_FESETROUND)
759 fpuState
= fegetround();
760 fesetround(FE_TOWARDZERO
);
761 #elif defined(HAVE__CONTROLFP)
762 fpuState
= _controlfp(_RC_CHOP
, _MCW_RC
);
769 /* Setup variables */
770 SamplesToDo
= min(size
, BUFFERSIZE
);
772 /* Clear mixing buffer */
773 memset(device
->DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
775 SuspendContext(NULL
);
776 ctx
= device
->Contexts
;
777 ctx_end
= ctx
+ device
->NumContexts
;
778 while(ctx
!= ctx_end
)
780 SuspendContext(*ctx
);
782 src
= (*ctx
)->ActiveSources
;
783 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
784 while(src
!= src_end
)
786 if((*src
)->state
!= AL_PLAYING
)
788 --((*ctx
)->ActiveSourceCount
);
793 if((*src
)->NeedsUpdate
)
795 ALsource_Update(*src
, *ctx
);
796 (*src
)->NeedsUpdate
= AL_FALSE
;
799 ALsource_Mix(*src
, device
, SamplesToDo
);
803 /* effect slot processing */
804 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
806 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
808 for(i
= 0;i
< SamplesToDo
;i
++)
810 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
811 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
815 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
816 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
819 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
820 SamplesToDo
, ALEffectSlot
->WetBuffer
,
823 for(i
= 0;i
< SamplesToDo
;i
++)
824 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
827 ProcessContext(*ctx
);
830 device
->SamplesPlayed
+= SamplesToDo
;
831 ProcessContext(NULL
);
833 //Post processing loop
834 for(i
= 0;i
< SamplesToDo
;i
++)
836 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
838 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
839 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
842 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
844 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
845 device
->PendingClicks
[i
] = 0.0f
;
848 switch(device
->Format
)
850 #define DO_WRITE(T, func, N, ...) do { \
851 const Channel chans[] = { \
854 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
855 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
856 const ALuint *ChanMap = device->DevChannels; \
858 for(i = 0;i < SamplesToDo;i++) \
860 for(j = 0;j < N;j++) \
862 ALfloat samp = 0.0f; \
863 for(c = 0;c < OUTPUTCHANNELS;c++) \
864 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
865 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
867 buffer = ((T*)buffer) + N; \
871 #define CHECK_WRITE_FORMAT(bits, T, func) \
872 case AL_FORMAT_MONO##bits: \
873 DO_WRITE(T, func, 1, FRONT_CENTER); \
875 case AL_FORMAT_STEREO##bits: \
878 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
879 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
880 const ALuint *ChanMap = device->DevChannels; \
882 for(i = 0;i < SamplesToDo;i++) \
884 float samples[2] = { 0.0f, 0.0f }; \
885 for(c = 0;c < OUTPUTCHANNELS;c++) \
887 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
888 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
890 bs2b_cross_feed(device->Bs2b, samples); \
891 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
892 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
893 buffer = ((T*)buffer) + 2; \
897 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
899 case AL_FORMAT_QUAD##bits: \
900 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
901 BACK_LEFT, BACK_RIGHT); \
903 case AL_FORMAT_51CHN##bits: \
904 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
906 BACK_LEFT, BACK_RIGHT); \
908 case AL_FORMAT_61CHN##bits: \
909 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
910 FRONT_CENTER, LFE, BACK_CENTER, \
911 SIDE_LEFT, SIDE_RIGHT); \
913 case AL_FORMAT_71CHN##bits: \
914 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
916 BACK_LEFT, BACK_RIGHT, \
917 SIDE_LEFT, SIDE_RIGHT); \
920 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
921 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
922 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
923 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
924 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
925 #undef AL_FORMAT_STEREO32
926 #undef AL_FORMAT_MONO32
927 #undef CHECK_WRITE_FORMAT
937 #if defined(HAVE_FESETROUND)
938 fesetround(fpuState
);
939 #elif defined(HAVE__CONTROLFP)
940 _controlfp(fpuState
, _MCW_RC
);