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 ALuint pos = DataPosInt; \
100 ALuint frac = DataPosFrac; \
101 ALfloat DrySend[OUTPUTCHANNELS]; \
107 DryFilter = &Source->Params.iirFilter; \
108 for(i = 0;i < OUTPUTCHANNELS;i++) \
109 DrySend[i] = Source->Params.DryGains[i]; \
113 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
115 value = lpFilter4PC(DryFilter, 0, value); \
116 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
117 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
118 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
119 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
120 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
121 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
122 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
123 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
125 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
127 /* First order interpolator */ \
128 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
130 /* Direct path final mix buffer and panning */ \
131 value = lpFilter4P(DryFilter, 0, value); \
132 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
133 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
134 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
135 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
136 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
137 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
138 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
139 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
142 pos += frac>>FRACTIONBITS; \
143 frac &= FRACTIONMASK; \
146 if(j == SamplesToDo) \
152 ALuint64 pos64 = pos; \
153 pos64 <<= FRACTIONBITS; \
155 pos64 -= increment; \
156 p = pos64>>FRACTIONBITS; \
157 f = pos64&FRACTIONMASK; \
159 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
161 value = lpFilter4PC(DryFilter, 0, value); \
162 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
163 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
164 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
165 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
166 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
167 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
168 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
169 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
172 for(out = 0;out < MAX_SENDS;out++) \
175 ALfloat *WetBuffer; \
176 ALfloat *WetClickRemoval; \
177 ALfloat *WetPendingClicks; \
180 if(!Source->Send[out].Slot || \
181 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
184 WetSend = Source->Params.WetGains[out]; \
185 WetBuffer = Source->Send[out].Slot->WetBuffer; \
186 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
187 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
188 WetFilter = &Source->Params.Send[out].iirFilter; \
191 frac = DataPosFrac; \
196 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
198 value = lpFilter2PC(WetFilter, 0, value); \
199 WetClickRemoval[0] -= value*WetSend; \
201 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
203 /* First order interpolator */ \
204 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
206 /* Room path final mix buffer and panning */ \
207 value = lpFilter2P(WetFilter, 0, value); \
208 WetBuffer[j] += value*WetSend; \
211 pos += frac>>FRACTIONBITS; \
212 frac &= FRACTIONMASK; \
215 if(j == SamplesToDo) \
221 ALuint64 pos64 = pos; \
222 pos64 <<= FRACTIONBITS; \
224 pos64 -= increment; \
225 p = pos64>>FRACTIONBITS; \
226 f = pos64&FRACTIONMASK; \
228 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
230 value = lpFilter2PC(WetFilter, 0, value); \
231 WetPendingClicks[0] += value*WetSend; \
235 DataPosFrac = frac; \
238 #define DO_MIX_STEREO(S,sampler) do { \
239 const ALfloat scaler = 1.0f/Channels; \
240 ALuint pos = DataPosInt; \
241 ALuint frac = DataPosFrac; \
242 ALfloat DrySend[OUTPUTCHANNELS]; \
248 DryFilter = &Source->Params.iirFilter; \
249 for(i = 0;i < OUTPUTCHANNELS;i++) \
250 DrySend[i] = Source->Params.DryGains[i]; \
254 for(i = 0;i < Channels;i++) \
256 value = sampler##S(Data.p##S[pos*Channels + i], \
257 Data.p##S[(pos+1)*Channels + i], frac); \
259 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
260 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
261 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
262 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
265 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
267 for(i = 0;i < Channels;i++) \
269 value = sampler##S(Data.p##S[pos*Channels + i], \
270 Data.p##S[(pos+1)*Channels + i], frac); \
272 value = lpFilter2P(DryFilter, chans[i]*2, value); \
273 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
274 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
275 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
279 pos += frac>>FRACTIONBITS; \
280 frac &= FRACTIONMASK; \
283 if(j == SamplesToDo) \
289 ALuint64 pos64 = pos; \
290 pos64 <<= FRACTIONBITS; \
292 pos64 -= increment; \
293 p = pos64>>FRACTIONBITS; \
294 f = pos64&FRACTIONMASK; \
296 for(i = 0;i < Channels;i++) \
298 value = sampler##S(Data.p##S[p*Channels + i], \
299 Data.p##S[(p+1)*Channels + i], f); \
301 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
302 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
303 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
304 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
308 for(out = 0;out < MAX_SENDS;out++) \
311 ALfloat *WetBuffer; \
312 ALfloat *WetClickRemoval; \
313 ALfloat *WetPendingClicks; \
316 if(!Source->Send[out].Slot || \
317 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
320 WetSend = Source->Params.WetGains[out]; \
321 WetBuffer = Source->Send[out].Slot->WetBuffer; \
322 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
323 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
324 WetFilter = &Source->Params.Send[out].iirFilter; \
327 frac = DataPosFrac; \
332 for(i = 0;i < Channels;i++) \
334 value = sampler##S(Data.p##S[pos*Channels + i], \
335 Data.p##S[(pos+1)*Channels + i], frac); \
337 value = lpFilter1PC(WetFilter, chans[i], value); \
338 WetClickRemoval[0] -= value*WetSend * scaler; \
341 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
343 for(i = 0;i < Channels;i++) \
345 value = sampler##S(Data.p##S[pos*Channels + i], \
346 Data.p##S[(pos+1)*Channels + i], frac); \
348 value = lpFilter1P(WetFilter, chans[i], value); \
349 WetBuffer[j] += value*WetSend * scaler; \
353 pos += frac>>FRACTIONBITS; \
354 frac &= FRACTIONMASK; \
357 if(j == SamplesToDo) \
363 ALuint64 pos64 = pos; \
364 pos64 <<= FRACTIONBITS; \
366 pos64 -= increment; \
367 p = pos64>>FRACTIONBITS; \
368 f = pos64&FRACTIONMASK; \
370 for(i = 0;i < Channels;i++) \
372 value = sampler##S(Data.p##S[p*Channels + i], \
373 Data.p##S[(p+1)*Channels + i], f); \
375 value = lpFilter1PC(WetFilter, chans[i], value); \
376 WetPendingClicks[0] += value*WetSend * scaler; \
381 DataPosFrac = frac; \
384 #define DO_MIX_MC(S,sampler) do { \
385 const ALfloat scaler = 1.0f/Channels; \
386 ALuint pos = DataPosInt; \
387 ALuint frac = DataPosFrac; \
388 ALfloat DrySend[OUTPUTCHANNELS]; \
394 DryFilter = &Source->Params.iirFilter; \
395 for(i = 0;i < OUTPUTCHANNELS;i++) \
396 DrySend[i] = Source->Params.DryGains[i]; \
400 for(i = 0;i < Channels;i++) \
402 value = sampler##S(Data.p##S[pos*Channels + i], \
403 Data.p##S[(pos+1)*Channels + i], frac); \
405 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
406 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
409 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
411 for(i = 0;i < Channels;i++) \
413 value = sampler##S(Data.p##S[pos*Channels + i], \
414 Data.p##S[(pos+1)*Channels + i], frac); \
416 value = lpFilter2P(DryFilter, chans[i]*2, value); \
417 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
421 pos += frac>>FRACTIONBITS; \
422 frac &= FRACTIONMASK; \
425 if(j == SamplesToDo) \
431 ALuint64 pos64 = pos; \
432 pos64 <<= FRACTIONBITS; \
434 pos64 -= increment; \
435 p = pos64>>FRACTIONBITS; \
436 f = pos64&FRACTIONMASK; \
438 for(i = 0;i < Channels;i++) \
440 value = sampler##S(Data.p##S[p*Channels + i], \
441 Data.p##S[(p+1)*Channels + i], f); \
443 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
444 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
448 for(out = 0;out < MAX_SENDS;out++) \
451 ALfloat *WetBuffer; \
452 ALfloat *WetClickRemoval; \
453 ALfloat *WetPendingClicks; \
456 if(!Source->Send[out].Slot || \
457 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
460 WetSend = Source->Params.WetGains[out]; \
461 WetBuffer = Source->Send[out].Slot->WetBuffer; \
462 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
463 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
464 WetFilter = &Source->Params.Send[out].iirFilter; \
467 frac = DataPosFrac; \
472 for(i = 0;i < Channels;i++) \
474 value = sampler##S(Data.p##S[pos*Channels + i], \
475 Data.p##S[(pos+1)*Channels + i], frac); \
477 value = lpFilter1PC(WetFilter, chans[i], value); \
478 WetClickRemoval[0] -= value*WetSend * scaler; \
481 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
483 for(i = 0;i < Channels;i++) \
485 value = sampler##S(Data.p##S[pos*Channels + i], \
486 Data.p##S[(pos+1)*Channels + i], frac); \
488 value = lpFilter1P(WetFilter, chans[i], value); \
489 WetBuffer[j] += value*WetSend * scaler; \
493 pos += frac>>FRACTIONBITS; \
494 frac &= FRACTIONMASK; \
497 if(j == SamplesToDo) \
503 ALuint64 pos64 = pos; \
504 pos64 <<= FRACTIONBITS; \
506 pos64 -= increment; \
507 p = pos64>>FRACTIONBITS; \
508 f = pos64&FRACTIONMASK; \
510 for(i = 0;i < Channels;i++) \
512 value = sampler##S(Data.p##S[p*Channels + i], \
513 Data.p##S[(p+1)*Channels + i], f); \
515 value = lpFilter1PC(WetFilter, chans[i], value); \
516 WetPendingClicks[0] += value*WetSend * scaler; \
521 DataPosFrac = frac; \
525 #define MIX_MONO(S) do { \
526 switch(Source->Resampler) \
528 case POINT_RESAMPLER: \
529 DO_MIX_MONO(S,point); break; \
530 case LINEAR_RESAMPLER: \
531 DO_MIX_MONO(S,lerp); break; \
532 case COSINE_RESAMPLER: \
533 DO_MIX_MONO(S,cos_lerp); break; \
534 case RESAMPLER_MIN: \
535 case RESAMPLER_MAX: \
540 #define MIX_STEREO(S) do { \
541 const int chans[] = { \
542 FRONT_LEFT, FRONT_RIGHT, \
543 SIDE_LEFT, SIDE_RIGHT, \
544 BACK_LEFT, BACK_RIGHT \
547 switch(Source->Resampler) \
549 case POINT_RESAMPLER: \
550 DO_MIX_STEREO(S,point); break; \
551 case LINEAR_RESAMPLER: \
552 DO_MIX_STEREO(S,lerp); break; \
553 case COSINE_RESAMPLER: \
554 DO_MIX_STEREO(S,cos_lerp); break; \
555 case RESAMPLER_MIN: \
556 case RESAMPLER_MAX: \
561 #define MIX_MC(S,...) do { \
562 const int chans[] = { __VA_ARGS__ }; \
564 switch(Source->Resampler) \
566 case POINT_RESAMPLER: \
567 DO_MIX_MC(S,point); break; \
568 case LINEAR_RESAMPLER: \
569 DO_MIX_MC(S,lerp); break; \
570 case COSINE_RESAMPLER: \
571 DO_MIX_MC(S,cos_lerp); break; \
572 case RESAMPLER_MIN: \
573 case RESAMPLER_MAX: \
579 #define MIX(S) do { \
580 if(Channels == 1) /* Mono */ \
582 else if(Channels == 2) /* Stereo */ \
584 else if(Channels == 4) /* Quad */ \
585 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
586 BACK_LEFT, BACK_RIGHT); \
587 else if(Channels == 6) /* 5.1 */ \
588 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
590 BACK_LEFT, BACK_RIGHT); \
591 else if(Channels == 7) /* 6.1 */ \
592 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
595 SIDE_LEFT, SIDE_RIGHT); \
596 else if(Channels == 8) /* 7.1 */ \
597 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
599 BACK_LEFT, BACK_RIGHT, \
600 SIDE_LEFT, SIDE_RIGHT); \
604 ALvoid
MixSource(ALsource
*Source
, ALuint SamplesToDo
,
605 ALfloat (*DryBuffer
)[OUTPUTCHANNELS
],
606 ALfloat
*ClickRemoval
, ALfloat
*PendingClicks
)
608 ALbufferlistitem
*BufferListItem
;
609 ALint64 DataSize64
,DataPos64
;
611 ALuint DataPosInt
, DataPosFrac
;
612 ALuint BuffersPlayed
;
617 /* Get source info */
618 State
= Source
->state
;
619 BuffersPlayed
= Source
->BuffersPlayed
;
620 DataPosInt
= Source
->position
;
621 DataPosFrac
= Source
->position_fraction
;
622 Looping
= Source
->bLooping
;
624 /* Get fixed point step */
625 increment
= Source
->Params
.Step
;
627 /* Get current buffer queue item */
628 BufferListItem
= Source
->queue
;
629 for(i
= 0;i
< BuffersPlayed
;i
++)
630 BufferListItem
= BufferListItem
->next
;
634 const ALbuffer
*ALBuffer
;
641 ALuint LoopStart
= 0;
643 ALuint Channels
, Bytes
;
646 /* Get buffer info */
647 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
649 Data
.p8
= ALBuffer
->data
;
650 DataSize
= ALBuffer
->size
;
651 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
652 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
653 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
657 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
659 /* If current pos is beyond the loop range, do not loop */
660 if(DataPosInt
>= LoopEnd
)
664 LoopStart
= ALBuffer
->LoopStart
;
665 LoopEnd
= ALBuffer
->LoopEnd
;
670 if(DataPosInt
>= DataSize
)
673 if(BufferListItem
->next
)
675 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
676 if(NextBuf
&& NextBuf
->size
)
678 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
679 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
680 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
681 NextBuf
->data
, ulExtraSamples
);
686 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
687 if(NextBuf
&& NextBuf
->size
)
689 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
690 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
691 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
692 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
697 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
699 /* Figure out how many samples we can mix. */
700 DataSize64
= LoopEnd
;
701 DataSize64
<<= FRACTIONBITS
;
702 DataPos64
= DataPosInt
;
703 DataPos64
<<= FRACTIONBITS
;
704 DataPos64
+= DataPosFrac
;
705 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
707 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
709 if(Bytes
== 4) /* 32-bit float */
711 else if(Bytes
== 2) /* signed 16-bit */
715 /* Handle looping sources */
716 if(DataPosInt
>= LoopEnd
)
718 if(BufferListItem
->next
)
720 BufferListItem
= BufferListItem
->next
;
722 DataPosInt
-= DataSize
;
726 BufferListItem
= Source
->queue
;
728 if(Source
->lSourceType
== AL_STATIC
)
729 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
731 DataPosInt
-= DataSize
;
736 BufferListItem
= Source
->queue
;
737 BuffersPlayed
= Source
->BuffersInQueue
;
742 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
744 /* Update source info */
745 Source
->state
= State
;
746 Source
->BuffersPlayed
= BuffersPlayed
;
747 Source
->position
= DataPosInt
;
748 Source
->position_fraction
= DataPosFrac
;
749 Source
->Buffer
= BufferListItem
->buffer
;
753 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
755 ALfloat (*DryBuffer
)[OUTPUTCHANNELS
];
756 ALfloat
*ClickRemoval
;
758 ALeffectslot
*ALEffectSlot
;
759 ALCcontext
**ctx
, **ctx_end
;
760 ALsource
**src
, **src_end
;
766 #if defined(HAVE_FESETROUND)
767 fpuState
= fegetround();
768 fesetround(FE_TOWARDZERO
);
769 #elif defined(HAVE__CONTROLFP)
770 fpuState
= _controlfp(0, 0);
771 _controlfp(_RC_CHOP
, _MCW_RC
);
776 DryBuffer
= device
->DryBuffer
;
779 /* Setup variables */
780 SamplesToDo
= min(size
, BUFFERSIZE
);
782 /* Clear mixing buffer */
783 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
785 SuspendContext(NULL
);
786 ctx
= device
->Contexts
;
787 ctx_end
= ctx
+ device
->NumContexts
;
788 while(ctx
!= ctx_end
)
790 SuspendContext(*ctx
);
792 src
= (*ctx
)->ActiveSources
;
793 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
794 while(src
!= src_end
)
796 if((*src
)->state
!= AL_PLAYING
)
798 --((*ctx
)->ActiveSourceCount
);
803 if((*src
)->NeedsUpdate
)
805 ALsource_Update(*src
, *ctx
);
806 (*src
)->NeedsUpdate
= AL_FALSE
;
809 ALsource_Mix(*src
, SamplesToDo
, DryBuffer
,
810 device
->ClickRemoval
, device
->PendingClicks
);
814 /* effect slot processing */
815 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
817 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
819 ClickRemoval
= ALEffectSlot
->ClickRemoval
;
820 for(i
= 0;i
< SamplesToDo
;i
++)
822 ClickRemoval
[0] -= ClickRemoval
[0] / 256.0f
;
823 ALEffectSlot
->WetBuffer
[i
] += ClickRemoval
[0];
827 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
828 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
831 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
, SamplesToDo
, ALEffectSlot
->WetBuffer
, DryBuffer
);
833 for(i
= 0;i
< SamplesToDo
;i
++)
834 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
837 ProcessContext(*ctx
);
840 device
->SamplesPlayed
+= SamplesToDo
;
841 ProcessContext(NULL
);
843 //Post processing loop
844 ClickRemoval
= device
->ClickRemoval
;
845 for(i
= 0;i
< SamplesToDo
;i
++)
847 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
849 ClickRemoval
[c
] -= ClickRemoval
[c
] / 256.0f
;
850 DryBuffer
[i
][c
] += ClickRemoval
[c
];
853 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
855 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
856 device
->PendingClicks
[i
] = 0.0f
;
859 switch(device
->Format
)
861 #define DO_WRITE(T, func, N, ...) do { \
862 const Channel chans[] = { \
865 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
866 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
867 const ALuint *ChanMap = device->DevChannels; \
869 for(i = 0;i < SamplesToDo;i++) \
871 for(j = 0;j < N;j++) \
874 for(c = 0;c < OUTPUTCHANNELS;c++) \
875 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
876 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
878 buffer = ((T*)buffer) + N; \
882 #define CHECK_WRITE_FORMAT(bits, T, func) \
883 case AL_FORMAT_MONO##bits: \
884 DO_WRITE(T, func, 1, FRONT_CENTER); \
886 case AL_FORMAT_STEREO##bits: \
889 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
890 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
891 const ALuint *ChanMap = device->DevChannels; \
893 for(i = 0;i < SamplesToDo;i++) \
895 float samples[2] = { 0.0f, 0.0f }; \
896 for(c = 0;c < OUTPUTCHANNELS;c++) \
898 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
899 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
901 bs2b_cross_feed(device->Bs2b, samples); \
902 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
903 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
904 buffer = ((T*)buffer) + 2; \
908 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
910 case AL_FORMAT_QUAD##bits: \
911 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
912 BACK_LEFT, BACK_RIGHT); \
914 case AL_FORMAT_51CHN##bits: \
915 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
917 BACK_LEFT, BACK_RIGHT); \
919 case AL_FORMAT_61CHN##bits: \
920 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
921 FRONT_CENTER, LFE, BACK_CENTER, \
922 SIDE_LEFT, SIDE_RIGHT); \
924 case AL_FORMAT_71CHN##bits: \
925 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
927 BACK_LEFT, BACK_RIGHT, \
928 SIDE_LEFT, SIDE_RIGHT); \
931 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
932 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
933 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
934 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
935 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
936 #undef AL_FORMAT_STEREO32
937 #undef AL_FORMAT_MONO32
938 #undef CHECK_WRITE_FORMAT
948 #if defined(HAVE_FESETROUND)
949 fesetround(fpuState
);
950 #elif defined(HAVE__CONTROLFP)
951 _controlfp(fpuState
, 0xfffff);