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
)
51 i
= (ALint
)(Value
*32768.0f
);
56 i
= (ALint
)(Value
*32767.0f
);
62 static __inline ALubyte
aluF2UB(ALfloat Value
)
64 ALshort i
= aluF2S(Value
);
69 static __inline ALfloat
point(ALfloat val1
, ALfloat val2
, ALint frac
)
75 static __inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALint frac
)
77 return val1
+ ((val2
-val1
)*(frac
* (1.0f
/(1<<FRACTIONBITS
))));
79 static __inline ALfloat
cos_lerp(ALfloat val1
, ALfloat val2
, ALint frac
)
81 ALfloat mult
= (1.0f
-cos(frac
* (1.0f
/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5f
;
82 return val1
+ ((val2
-val1
)*mult
);
86 static void MixSource(ALsource
*ALSource
, ALCcontext
*ALContext
,
87 float (*DryBuffer
)[OUTPUTCHANNELS
], ALuint SamplesToDo
)
89 static float DummyBuffer
[BUFFERSIZE
];
90 static ALfloat DummyClickRemoval
[OUTPUTCHANNELS
];
91 ALfloat
*WetBuffer
[MAX_SENDS
];
92 ALfloat DrySend
[OUTPUTCHANNELS
];
93 ALfloat
*ClickRemoval
, *PendingClicks
;
94 ALfloat
*WetClickRemoval
[MAX_SENDS
];
95 ALfloat
*WetPendingClicks
[MAX_SENDS
];
97 ALfloat value
, outsamp
;
98 ALbufferlistitem
*BufferListItem
;
99 ALint64 DataSize64
,DataPos64
;
100 FILTER
*DryFilter
, *WetFilter
[MAX_SENDS
];
101 ALfloat WetSend
[MAX_SENDS
];
103 ALuint DataPosInt
, DataPosFrac
;
104 resampler_t Resampler
;
105 ALuint BuffersPlayed
;
109 ClickRemoval
= ALContext
->Device
->ClickRemoval
;
110 PendingClicks
= ALContext
->Device
->PendingClicks
;
112 if(ALSource
->NeedsUpdate
)
114 ALsource_Update(ALSource
, ALContext
);
115 ALSource
->NeedsUpdate
= AL_FALSE
;
118 /* Get source info */
119 Resampler
= ALSource
->Resampler
;
120 State
= ALSource
->state
;
121 BuffersPlayed
= ALSource
->BuffersPlayed
;
122 DataPosInt
= ALSource
->position
;
123 DataPosFrac
= ALSource
->position_fraction
;
124 Looping
= ALSource
->bLooping
;
126 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
127 DrySend
[i
] = ALSource
->Params
.DryGains
[i
];
128 for(i
= 0;i
< MAX_SENDS
;i
++)
129 WetSend
[i
] = ALSource
->Params
.WetGains
[i
];
131 /* Get fixed point step */
132 increment
= ALSource
->Params
.Step
;
134 DryFilter
= &ALSource
->Params
.iirFilter
;
135 for(i
= 0;i
< MAX_SENDS
;i
++)
137 WetFilter
[i
] = &ALSource
->Params
.Send
[i
].iirFilter
;
138 WetBuffer
[i
] = (ALSource
->Send
[i
].Slot
?
139 ALSource
->Send
[i
].Slot
->WetBuffer
:
141 WetClickRemoval
[i
] = (ALSource
->Send
[i
].Slot
?
142 ALSource
->Send
[i
].Slot
->ClickRemoval
:
144 WetPendingClicks
[i
] = (ALSource
->Send
[i
].Slot
?
145 ALSource
->Send
[i
].Slot
->PendingClicks
:
149 /* Get current buffer queue item */
150 BufferListItem
= ALSource
->queue
;
151 for(i
= 0;i
< BuffersPlayed
;i
++)
152 BufferListItem
= BufferListItem
->next
;
156 const ALbuffer
*ALBuffer
;
157 ALfloat
*Data
= NULL
;
159 ALuint LoopStart
= 0;
161 ALuint Channels
, Bytes
;
164 /* Get buffer info */
165 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
167 Data
= ALBuffer
->data
;
168 DataSize
= ALBuffer
->size
;
169 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
170 LoopStart
= ALBuffer
->LoopStart
;
171 LoopEnd
= ALBuffer
->LoopEnd
;
172 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
173 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
176 if(Looping
&& ALSource
->lSourceType
== AL_STATIC
)
178 /* If current offset is beyond the loop range, do not loop */
179 if(DataPosInt
>= LoopEnd
)
182 if(!Looping
|| ALSource
->lSourceType
!= AL_STATIC
)
184 /* Non-looping and non-static sources ignore loop points */
189 if(DataPosInt
>= DataSize
)
192 if(BufferListItem
->next
)
194 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
195 if(NextBuf
&& NextBuf
->size
)
197 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
198 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
199 memcpy(&Data
[DataSize
*Channels
], NextBuf
->data
, ulExtraSamples
);
204 ALbuffer
*NextBuf
= ALSource
->queue
->buffer
;
205 if(NextBuf
&& NextBuf
->size
)
207 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
208 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
209 memcpy(&Data
[DataSize
*Channels
], &NextBuf
->data
[LoopStart
*Channels
], ulExtraSamples
);
213 memset(&Data
[DataSize
*Channels
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
215 /* Figure out how many samples we can mix. */
216 DataSize64
= LoopEnd
;
217 DataSize64
<<= FRACTIONBITS
;
218 DataPos64
= DataPosInt
;
219 DataPos64
<<= FRACTIONBITS
;
220 DataPos64
+= DataPosFrac
;
221 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
223 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
225 /* Actual sample mixing loops */
226 if(Channels
== 1) /* Mono */
228 #define DO_MIX(resampler) do { \
231 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
234 outsamp = lpFilter4PC(DryFilter, 0, value); \
235 ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \
236 ClickRemoval[FRONT_RIGHT] -= outsamp*DrySend[FRONT_RIGHT]; \
237 ClickRemoval[SIDE_LEFT] -= outsamp*DrySend[SIDE_LEFT]; \
238 ClickRemoval[SIDE_RIGHT] -= outsamp*DrySend[SIDE_RIGHT]; \
239 ClickRemoval[BACK_LEFT] -= outsamp*DrySend[BACK_LEFT]; \
240 ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \
241 ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \
242 ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \
244 for(out = 0;out < MAX_SENDS;out++) \
246 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
247 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
250 while(BufferSize--) \
252 /* First order interpolator */ \
253 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
256 /* Direct path final mix buffer and panning */ \
257 outsamp = lpFilter4P(DryFilter, 0, value); \
258 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
259 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
260 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
261 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
262 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
263 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
264 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
265 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
267 /* Room path final mix buffer and panning */ \
268 for(i = 0;i < MAX_SENDS;i++) \
270 outsamp = lpFilter2P(WetFilter[i], 0, value); \
271 WetBuffer[i][j] += outsamp*WetSend[i]; \
274 DataPosFrac += increment; \
275 DataPosInt += DataPosFrac>>FRACTIONBITS; \
276 DataPosFrac &= FRACTIONMASK; \
279 if(j == SamplesToDo) \
281 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
282 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
283 ((DataPosFrac-increment)&FRACTIONMASK)); \
284 value = (resampler)(Data[pos], Data[pos+1], frac); \
286 outsamp = lpFilter4PC(DryFilter, 0, value); \
287 PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
288 PendingClicks[FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
289 PendingClicks[SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
290 PendingClicks[SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
291 PendingClicks[BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
292 PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
293 PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
294 PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
296 for(out = 0;out < MAX_SENDS;out++) \
298 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
299 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
306 case POINT_RESAMPLER
:
307 DO_MIX(point
); break;
308 case LINEAR_RESAMPLER
:
310 case COSINE_RESAMPLER
:
311 DO_MIX(cos_lerp
); break;
318 else if(Channels
== 2) /* Stereo */
320 const int chans
[] = {
321 FRONT_LEFT
, FRONT_RIGHT
,
322 SIDE_LEFT
, SIDE_RIGHT
,
323 BACK_LEFT
, BACK_RIGHT
326 #define DO_MIX(resampler) do { \
327 const ALfloat scaler = 1.0f/Channels; \
330 for(i = 0;i < Channels;i++) \
332 value = (resampler)(Data[DataPosInt*Channels + i], \
333 Data[(DataPosInt+1)*Channels + i], \
336 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
337 ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \
338 ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \
339 ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \
341 for(out = 0;out < MAX_SENDS;out++) \
343 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
344 WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \
348 while(BufferSize--) \
350 for(i = 0;i < Channels;i++) \
352 value = (resampler)(Data[DataPosInt*Channels + i], \
353 Data[(DataPosInt+1)*Channels + i], \
356 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
357 DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
358 DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
359 DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
361 for(out = 0;out < MAX_SENDS;out++) \
363 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
364 WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \
368 DataPosFrac += increment; \
369 DataPosInt += DataPosFrac>>FRACTIONBITS; \
370 DataPosFrac &= FRACTIONMASK; \
373 if(j == SamplesToDo) \
375 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
376 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
377 ((DataPosFrac-increment)&FRACTIONMASK)); \
378 for(i = 0;i < Channels;i++) \
380 value = (resampler)(Data[pos*Channels + i], \
381 Data[(pos+1)*Channels + i], \
384 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
385 PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
386 PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
387 PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
389 for(out = 0;out < MAX_SENDS;out++) \
391 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
392 WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \
400 case POINT_RESAMPLER
:
401 DO_MIX(point
); break;
402 case LINEAR_RESAMPLER
:
404 case COSINE_RESAMPLER
:
405 DO_MIX(cos_lerp
); break;
412 else if(Channels
== 4) /* Quad */
414 const int chans
[] = {
415 FRONT_LEFT
, FRONT_RIGHT
,
416 BACK_LEFT
, BACK_RIGHT
419 #define DO_MIX(resampler) do { \
420 const ALfloat scaler = 1.0f/Channels; \
423 for(i = 0;i < Channels;i++) \
425 value = (resampler)(Data[DataPosInt*Channels + i], \
426 Data[(DataPosInt+1)*Channels + i], \
429 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
430 ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \
432 for(out = 0;out < MAX_SENDS;out++) \
434 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
435 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
439 while(BufferSize--) \
441 for(i = 0;i < Channels;i++) \
443 value = (resampler)(Data[DataPosInt*Channels + i], \
444 Data[(DataPosInt+1)*Channels + i], \
447 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
448 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
450 for(out = 0;out < MAX_SENDS;out++) \
452 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
453 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
457 DataPosFrac += increment; \
458 DataPosInt += DataPosFrac>>FRACTIONBITS; \
459 DataPosFrac &= FRACTIONMASK; \
462 if(j == SamplesToDo) \
464 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
465 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
466 ((DataPosFrac-increment)&FRACTIONMASK)); \
467 for(i = 0;i < Channels;i++) \
469 value = (resampler)(Data[pos*Channels + i], \
470 Data[(pos+1)*Channels + i], \
473 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
474 PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \
476 for(out = 0;out < MAX_SENDS;out++) \
478 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
479 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
487 case POINT_RESAMPLER
:
488 DO_MIX(point
); break;
489 case LINEAR_RESAMPLER
:
491 case COSINE_RESAMPLER
:
492 DO_MIX(cos_lerp
); break;
498 else if(Channels
== 6) /* 5.1 */
500 const int chans
[] = {
501 FRONT_LEFT
, FRONT_RIGHT
,
503 BACK_LEFT
, BACK_RIGHT
508 case POINT_RESAMPLER
:
509 DO_MIX(point
); break;
510 case LINEAR_RESAMPLER
:
512 case COSINE_RESAMPLER
:
513 DO_MIX(cos_lerp
); break;
519 else if(Channels
== 7) /* 6.1 */
521 const int chans
[] = {
522 FRONT_LEFT
, FRONT_RIGHT
,
525 SIDE_LEFT
, SIDE_RIGHT
530 case POINT_RESAMPLER
:
531 DO_MIX(point
); break;
532 case LINEAR_RESAMPLER
:
534 case COSINE_RESAMPLER
:
535 DO_MIX(cos_lerp
); break;
541 else if(Channels
== 8) /* 7.1 */
543 const int chans
[] = {
544 FRONT_LEFT
, FRONT_RIGHT
,
546 BACK_LEFT
, BACK_RIGHT
,
547 SIDE_LEFT
, SIDE_RIGHT
552 case POINT_RESAMPLER
:
553 DO_MIX(point
); break;
554 case LINEAR_RESAMPLER
:
556 case COSINE_RESAMPLER
:
557 DO_MIX(cos_lerp
); break;
568 DataPosFrac
+= increment
;
569 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
570 DataPosFrac
&= FRACTIONMASK
;
576 /* Handle looping sources */
577 if(DataPosInt
>= LoopEnd
)
579 if(BuffersPlayed
< (ALSource
->BuffersInQueue
-1))
581 BufferListItem
= BufferListItem
->next
;
583 DataPosInt
-= DataSize
;
587 BufferListItem
= ALSource
->queue
;
589 if(ALSource
->lSourceType
== AL_STATIC
)
590 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
592 DataPosInt
-= DataSize
;
597 BufferListItem
= ALSource
->queue
;
598 BuffersPlayed
= ALSource
->BuffersInQueue
;
603 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
605 /* Update source info */
606 ALSource
->state
= State
;
607 ALSource
->BuffersPlayed
= BuffersPlayed
;
608 ALSource
->position
= DataPosInt
;
609 ALSource
->position_fraction
= DataPosFrac
;
610 ALSource
->Buffer
= BufferListItem
->buffer
;
612 ALSource
->FirstStart
= AL_FALSE
;
615 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
617 float (*DryBuffer
)[OUTPUTCHANNELS
];
618 ALfloat (*Matrix
)[OUTPUTCHANNELS
];
619 ALfloat
*ClickRemoval
;
620 const ALuint
*ChanMap
;
622 ALeffectslot
*ALEffectSlot
;
623 ALCcontext
*ALContext
;
629 #if defined(HAVE_FESETROUND)
630 fpuState
= fegetround();
631 fesetround(FE_TOWARDZERO
);
632 #elif defined(HAVE__CONTROLFP)
633 fpuState
= _controlfp(0, 0);
634 _controlfp(_RC_CHOP
, _MCW_RC
);
639 DryBuffer
= device
->DryBuffer
;
642 /* Setup variables */
643 SamplesToDo
= min(size
, BUFFERSIZE
);
645 /* Clear mixing buffer */
646 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
648 SuspendContext(NULL
);
649 for(c
= 0;c
< device
->NumContexts
;c
++)
651 ALContext
= device
->Contexts
[c
];
652 SuspendContext(ALContext
);
655 while(s
< ALContext
->ActiveSourceCount
)
657 ALsource
*Source
= ALContext
->ActiveSources
[s
];
658 if(Source
->state
!= AL_PLAYING
)
660 ALsizei end
= --(ALContext
->ActiveSourceCount
);
661 ALContext
->ActiveSources
[s
] = ALContext
->ActiveSources
[end
];
664 MixSource(Source
, ALContext
, DryBuffer
, SamplesToDo
);
668 /* effect slot processing */
669 for(e
= 0;e
< ALContext
->EffectSlotMap
.size
;e
++)
671 ALEffectSlot
= ALContext
->EffectSlotMap
.array
[e
].value
;
673 ClickRemoval
= ALEffectSlot
->ClickRemoval
;
674 for(i
= 0;i
< SamplesToDo
;i
++)
676 ClickRemoval
[0] -= ClickRemoval
[0] / 256.0f
;
677 ALEffectSlot
->WetBuffer
[i
] += ClickRemoval
[0];
681 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
682 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
685 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
, SamplesToDo
, ALEffectSlot
->WetBuffer
, DryBuffer
);
687 for(i
= 0;i
< SamplesToDo
;i
++)
688 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
690 ProcessContext(ALContext
);
692 device
->SamplesPlayed
+= SamplesToDo
;
693 ProcessContext(NULL
);
695 //Post processing loop
696 ClickRemoval
= device
->ClickRemoval
;
697 for(i
= 0;i
< SamplesToDo
;i
++)
699 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
701 ClickRemoval
[c
] -= ClickRemoval
[c
] / 256.0f
;
702 DryBuffer
[i
][c
] += ClickRemoval
[c
];
705 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
707 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
708 device
->PendingClicks
[i
] = 0.0f
;
711 ChanMap
= device
->DevChannels
;
712 Matrix
= device
->ChannelMatrix
;
713 switch(device
->Format
)
715 #define CHECK_WRITE_FORMAT(bits, type, func) \
716 case AL_FORMAT_MONO##bits: \
717 for(i = 0;i < SamplesToDo;i++) \
720 for(c = 0;c < OUTPUTCHANNELS;c++) \
721 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
722 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
723 buffer = ((type*)buffer) + 1; \
726 case AL_FORMAT_STEREO##bits: \
729 for(i = 0;i < SamplesToDo;i++) \
731 float samples[2] = { 0.0f, 0.0f }; \
732 for(c = 0;c < OUTPUTCHANNELS;c++) \
734 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
735 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
737 bs2b_cross_feed(device->Bs2b, samples); \
738 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
739 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
740 buffer = ((type*)buffer) + 2; \
745 for(i = 0;i < SamplesToDo;i++) \
747 static const Channel chans[] = { \
748 FRONT_LEFT, FRONT_RIGHT \
750 for(j = 0;j < 2;j++) \
753 for(c = 0;c < OUTPUTCHANNELS;c++) \
754 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
755 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
757 buffer = ((type*)buffer) + 2; \
761 case AL_FORMAT_QUAD##bits: \
762 for(i = 0;i < SamplesToDo;i++) \
764 static const Channel chans[] = { \
765 FRONT_LEFT, FRONT_RIGHT, \
766 BACK_LEFT, BACK_RIGHT, \
768 for(j = 0;j < 4;j++) \
771 for(c = 0;c < OUTPUTCHANNELS;c++) \
772 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
773 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
775 buffer = ((type*)buffer) + 4; \
778 case AL_FORMAT_51CHN##bits: \
779 for(i = 0;i < SamplesToDo;i++) \
781 static const Channel chans[] = { \
782 FRONT_LEFT, FRONT_RIGHT, \
784 BACK_LEFT, BACK_RIGHT, \
786 for(j = 0;j < 6;j++) \
789 for(c = 0;c < OUTPUTCHANNELS;c++) \
790 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
791 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
793 buffer = ((type*)buffer) + 6; \
796 case AL_FORMAT_61CHN##bits: \
797 for(i = 0;i < SamplesToDo;i++) \
799 static const Channel chans[] = { \
800 FRONT_LEFT, FRONT_RIGHT, \
801 FRONT_CENTER, LFE, BACK_CENTER, \
802 SIDE_LEFT, SIDE_RIGHT, \
804 for(j = 0;j < 7;j++) \
807 for(c = 0;c < OUTPUTCHANNELS;c++) \
808 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
809 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
811 buffer = ((type*)buffer) + 7; \
814 case AL_FORMAT_71CHN##bits: \
815 for(i = 0;i < SamplesToDo;i++) \
817 static const Channel chans[] = { \
818 FRONT_LEFT, FRONT_RIGHT, \
820 BACK_LEFT, BACK_RIGHT, \
821 SIDE_LEFT, SIDE_RIGHT \
823 for(j = 0;j < 8;j++) \
826 for(c = 0;c < OUTPUTCHANNELS;c++) \
827 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
828 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
830 buffer = ((type*)buffer) + 8; \
834 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
835 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
836 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
837 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
838 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
839 #undef AL_FORMAT_STEREO32
840 #undef AL_FORMAT_MONO32
841 #undef CHECK_WRITE_FORMAT
850 #if defined(HAVE_FESETROUND)
851 fesetround(fpuState
);
852 #elif defined(HAVE__CONTROLFP)
853 _controlfp(fpuState
, 0xfffff);