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
< 0.0f
) i
= (ALint
)(Value
*32768.0f
);
51 else if(Value
> 1.0f
) i
= 32767;
52 else if(Value
> 0.0f
) i
= (ALint
)(Value
*32767.0f
);
57 static __inline ALubyte
aluF2UB(ALfloat Value
)
59 ALshort i
= aluF2S(Value
);
64 static __inline ALfloat
point(ALfloat val1
, ALfloat val2
, ALint frac
)
70 static __inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALint frac
)
72 return val1
+ ((val2
-val1
)*(frac
* (1.0f
/(1<<FRACTIONBITS
))));
74 static __inline ALfloat
cos_lerp(ALfloat val1
, ALfloat val2
, ALint frac
)
76 ALfloat mult
= (1.0f
-cos(frac
* (1.0f
/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5f
;
77 return val1
+ ((val2
-val1
)*mult
);
81 static void MixSource(ALsource
*ALSource
, ALCcontext
*ALContext
,
82 float (*DryBuffer
)[OUTPUTCHANNELS
], ALuint SamplesToDo
,
83 ALfloat
*ClickRemoval
, ALfloat
*PendingClicks
)
85 static float DummyBuffer
[BUFFERSIZE
];
86 static ALfloat DummyClickRemoval
[OUTPUTCHANNELS
];
87 ALfloat
*WetBuffer
[MAX_SENDS
];
88 ALfloat DrySend
[OUTPUTCHANNELS
];
89 ALfloat
*WetClickRemoval
[MAX_SENDS
];
90 ALfloat
*WetPendingClicks
[MAX_SENDS
];
92 ALfloat value
, outsamp
;
93 ALbufferlistitem
*BufferListItem
;
94 ALint64 DataSize64
,DataPos64
;
95 FILTER
*DryFilter
, *WetFilter
[MAX_SENDS
];
96 ALfloat WetSend
[MAX_SENDS
];
98 ALuint DataPosInt
, DataPosFrac
;
99 resampler_t Resampler
;
100 ALuint BuffersPlayed
;
104 if(ALSource
->NeedsUpdate
)
106 ALsource_Update(ALSource
, ALContext
);
107 ALSource
->NeedsUpdate
= AL_FALSE
;
110 /* Get source info */
111 Resampler
= ALSource
->Resampler
;
112 State
= ALSource
->state
;
113 BuffersPlayed
= ALSource
->BuffersPlayed
;
114 DataPosInt
= ALSource
->position
;
115 DataPosFrac
= ALSource
->position_fraction
;
116 Looping
= ALSource
->bLooping
;
118 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
119 DrySend
[i
] = ALSource
->Params
.DryGains
[i
];
120 for(i
= 0;i
< MAX_SENDS
;i
++)
121 WetSend
[i
] = ALSource
->Params
.WetGains
[i
];
123 /* Get fixed point step */
124 increment
= ALSource
->Params
.Step
;
126 DryFilter
= &ALSource
->Params
.iirFilter
;
127 for(i
= 0;i
< MAX_SENDS
;i
++)
129 WetFilter
[i
] = &ALSource
->Params
.Send
[i
].iirFilter
;
130 if(ALSource
->Send
[i
].Slot
)
132 WetBuffer
[i
] = ALSource
->Send
[i
].Slot
->WetBuffer
;
133 WetClickRemoval
[i
] = ALSource
->Send
[i
].Slot
->ClickRemoval
;
134 WetPendingClicks
[i
] = ALSource
->Send
[i
].Slot
->PendingClicks
;
138 WetBuffer
[i
] = DummyBuffer
;
139 WetClickRemoval
[i
] = DummyClickRemoval
;
140 WetPendingClicks
[i
] = DummyClickRemoval
;
144 /* Get current buffer queue item */
145 BufferListItem
= ALSource
->queue
;
146 for(i
= 0;i
< BuffersPlayed
;i
++)
147 BufferListItem
= BufferListItem
->next
;
151 const ALbuffer
*ALBuffer
;
152 ALfloat
*Data
= NULL
;
154 ALuint LoopStart
= 0;
156 ALuint Channels
, Bytes
;
159 /* Get buffer info */
160 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
162 Data
= ALBuffer
->data
;
163 DataSize
= ALBuffer
->size
;
164 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
165 LoopStart
= ALBuffer
->LoopStart
;
166 LoopEnd
= ALBuffer
->LoopEnd
;
167 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
168 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
171 if(Looping
&& ALSource
->lSourceType
== AL_STATIC
)
173 /* If current offset is beyond the loop range, do not loop */
174 if(DataPosInt
>= LoopEnd
)
177 if(!Looping
|| ALSource
->lSourceType
!= AL_STATIC
)
179 /* Non-looping and non-static sources ignore loop points */
184 if(DataPosInt
>= DataSize
)
187 if(BufferListItem
->next
)
189 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
190 if(NextBuf
&& NextBuf
->size
)
192 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
193 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
194 memcpy(&Data
[DataSize
*Channels
], NextBuf
->data
, ulExtraSamples
);
199 ALbuffer
*NextBuf
= ALSource
->queue
->buffer
;
200 if(NextBuf
&& NextBuf
->size
)
202 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
203 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
204 memcpy(&Data
[DataSize
*Channels
], &NextBuf
->data
[LoopStart
*Channels
], ulExtraSamples
);
208 memset(&Data
[DataSize
*Channels
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
210 /* Figure out how many samples we can mix. */
211 DataSize64
= LoopEnd
;
212 DataSize64
<<= FRACTIONBITS
;
213 DataPos64
= DataPosInt
;
214 DataPos64
<<= FRACTIONBITS
;
215 DataPos64
+= DataPosFrac
;
216 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
218 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
220 /* Actual sample mixing loops */
221 if(Channels
== 1) /* Mono */
223 #define DO_MIX(resampler) do { \
226 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
229 outsamp = lpFilter4PC(DryFilter, 0, value); \
230 ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \
231 ClickRemoval[FRONT_RIGHT] -= outsamp*DrySend[FRONT_RIGHT]; \
232 ClickRemoval[SIDE_LEFT] -= outsamp*DrySend[SIDE_LEFT]; \
233 ClickRemoval[SIDE_RIGHT] -= outsamp*DrySend[SIDE_RIGHT]; \
234 ClickRemoval[BACK_LEFT] -= outsamp*DrySend[BACK_LEFT]; \
235 ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \
236 ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \
237 ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \
239 for(out = 0;out < MAX_SENDS;out++) \
241 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
242 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
245 while(BufferSize--) \
247 /* First order interpolator */ \
248 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
251 /* Direct path final mix buffer and panning */ \
252 outsamp = lpFilter4P(DryFilter, 0, value); \
253 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
254 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
255 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
256 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
257 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
258 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
259 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
260 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
262 /* Room path final mix buffer and panning */ \
263 for(i = 0;i < MAX_SENDS;i++) \
265 outsamp = lpFilter2P(WetFilter[i], 0, value); \
266 WetBuffer[i][j] += outsamp*WetSend[i]; \
269 DataPosFrac += increment; \
270 DataPosInt += DataPosFrac>>FRACTIONBITS; \
271 DataPosFrac &= FRACTIONMASK; \
274 if(j == SamplesToDo) \
276 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
277 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
278 ((DataPosFrac-increment)&FRACTIONMASK)); \
279 value = (resampler)(Data[pos], Data[pos+1], frac); \
281 outsamp = lpFilter4PC(DryFilter, 0, value); \
282 PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
283 PendingClicks[FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
284 PendingClicks[SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
285 PendingClicks[SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
286 PendingClicks[BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
287 PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
288 PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
289 PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
291 for(out = 0;out < MAX_SENDS;out++) \
293 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
294 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
301 case POINT_RESAMPLER
:
302 DO_MIX(point
); break;
303 case LINEAR_RESAMPLER
:
305 case COSINE_RESAMPLER
:
306 DO_MIX(cos_lerp
); break;
313 else if(Channels
== 2) /* Stereo */
315 const int chans
[] = {
316 FRONT_LEFT
, FRONT_RIGHT
,
317 SIDE_LEFT
, SIDE_RIGHT
,
318 BACK_LEFT
, BACK_RIGHT
321 #define DO_MIX(resampler) do { \
322 const ALfloat scaler = 1.0f/Channels; \
325 for(i = 0;i < Channels;i++) \
327 value = (resampler)(Data[DataPosInt*Channels + i], \
328 Data[(DataPosInt+1)*Channels + i], \
331 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
332 ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \
333 ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \
334 ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \
336 for(out = 0;out < MAX_SENDS;out++) \
338 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
339 WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \
343 while(BufferSize--) \
345 for(i = 0;i < Channels;i++) \
347 value = (resampler)(Data[DataPosInt*Channels + i], \
348 Data[(DataPosInt+1)*Channels + i], \
351 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
352 DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
353 DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
354 DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
356 for(out = 0;out < MAX_SENDS;out++) \
358 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
359 WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \
363 DataPosFrac += increment; \
364 DataPosInt += DataPosFrac>>FRACTIONBITS; \
365 DataPosFrac &= FRACTIONMASK; \
368 if(j == SamplesToDo) \
370 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
371 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
372 ((DataPosFrac-increment)&FRACTIONMASK)); \
373 for(i = 0;i < Channels;i++) \
375 value = (resampler)(Data[pos*Channels + i], \
376 Data[(pos+1)*Channels + i], \
379 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
380 PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
381 PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
382 PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
384 for(out = 0;out < MAX_SENDS;out++) \
386 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
387 WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \
395 case POINT_RESAMPLER
:
396 DO_MIX(point
); break;
397 case LINEAR_RESAMPLER
:
399 case COSINE_RESAMPLER
:
400 DO_MIX(cos_lerp
); break;
407 else if(Channels
== 4) /* Quad */
409 const int chans
[] = {
410 FRONT_LEFT
, FRONT_RIGHT
,
411 BACK_LEFT
, BACK_RIGHT
414 #define DO_MIX(resampler) do { \
415 const ALfloat scaler = 1.0f/Channels; \
418 for(i = 0;i < Channels;i++) \
420 value = (resampler)(Data[DataPosInt*Channels + i], \
421 Data[(DataPosInt+1)*Channels + i], \
424 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
425 ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \
427 for(out = 0;out < MAX_SENDS;out++) \
429 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
430 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
434 while(BufferSize--) \
436 for(i = 0;i < Channels;i++) \
438 value = (resampler)(Data[DataPosInt*Channels + i], \
439 Data[(DataPosInt+1)*Channels + i], \
442 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
443 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
445 for(out = 0;out < MAX_SENDS;out++) \
447 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
448 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
452 DataPosFrac += increment; \
453 DataPosInt += DataPosFrac>>FRACTIONBITS; \
454 DataPosFrac &= FRACTIONMASK; \
457 if(j == SamplesToDo) \
459 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
460 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
461 ((DataPosFrac-increment)&FRACTIONMASK)); \
462 for(i = 0;i < Channels;i++) \
464 value = (resampler)(Data[pos*Channels + i], \
465 Data[(pos+1)*Channels + i], \
468 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
469 PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \
471 for(out = 0;out < MAX_SENDS;out++) \
473 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
474 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
482 case POINT_RESAMPLER
:
483 DO_MIX(point
); break;
484 case LINEAR_RESAMPLER
:
486 case COSINE_RESAMPLER
:
487 DO_MIX(cos_lerp
); break;
493 else if(Channels
== 6) /* 5.1 */
495 const int chans
[] = {
496 FRONT_LEFT
, FRONT_RIGHT
,
498 BACK_LEFT
, BACK_RIGHT
503 case POINT_RESAMPLER
:
504 DO_MIX(point
); break;
505 case LINEAR_RESAMPLER
:
507 case COSINE_RESAMPLER
:
508 DO_MIX(cos_lerp
); break;
514 else if(Channels
== 7) /* 6.1 */
516 const int chans
[] = {
517 FRONT_LEFT
, FRONT_RIGHT
,
520 SIDE_LEFT
, SIDE_RIGHT
525 case POINT_RESAMPLER
:
526 DO_MIX(point
); break;
527 case LINEAR_RESAMPLER
:
529 case COSINE_RESAMPLER
:
530 DO_MIX(cos_lerp
); break;
536 else if(Channels
== 8) /* 7.1 */
538 const int chans
[] = {
539 FRONT_LEFT
, FRONT_RIGHT
,
541 BACK_LEFT
, BACK_RIGHT
,
542 SIDE_LEFT
, SIDE_RIGHT
547 case POINT_RESAMPLER
:
548 DO_MIX(point
); break;
549 case LINEAR_RESAMPLER
:
551 case COSINE_RESAMPLER
:
552 DO_MIX(cos_lerp
); break;
563 DataPosFrac
+= increment
;
564 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
565 DataPosFrac
&= FRACTIONMASK
;
571 /* Handle looping sources */
572 if(DataPosInt
>= LoopEnd
)
574 if(BuffersPlayed
< (ALSource
->BuffersInQueue
-1))
576 BufferListItem
= BufferListItem
->next
;
578 DataPosInt
-= DataSize
;
582 BufferListItem
= ALSource
->queue
;
584 if(ALSource
->lSourceType
== AL_STATIC
)
585 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
587 DataPosInt
-= DataSize
;
592 BufferListItem
= ALSource
->queue
;
593 BuffersPlayed
= ALSource
->BuffersInQueue
;
598 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
600 /* Update source info */
601 ALSource
->state
= State
;
602 ALSource
->BuffersPlayed
= BuffersPlayed
;
603 ALSource
->position
= DataPosInt
;
604 ALSource
->position_fraction
= DataPosFrac
;
605 ALSource
->Buffer
= BufferListItem
->buffer
;
608 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
610 float (*DryBuffer
)[OUTPUTCHANNELS
];
611 ALfloat (*Matrix
)[OUTPUTCHANNELS
];
612 ALfloat
*ClickRemoval
;
613 const ALuint
*ChanMap
;
615 ALeffectslot
*ALEffectSlot
;
616 ALCcontext
**ctx
, **ctx_end
;
617 ALsource
**src
, **src_end
;
623 #if defined(HAVE_FESETROUND)
624 fpuState
= fegetround();
625 fesetround(FE_TOWARDZERO
);
626 #elif defined(HAVE__CONTROLFP)
627 fpuState
= _controlfp(0, 0);
628 _controlfp(_RC_CHOP
, _MCW_RC
);
633 DryBuffer
= device
->DryBuffer
;
636 /* Setup variables */
637 SamplesToDo
= min(size
, BUFFERSIZE
);
639 /* Clear mixing buffer */
640 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
642 SuspendContext(NULL
);
643 ctx
= device
->Contexts
;
644 ctx_end
= ctx
+ device
->NumContexts
;
645 while(ctx
!= ctx_end
)
647 SuspendContext(*ctx
);
649 src
= (*ctx
)->ActiveSources
;
650 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
651 while(src
!= src_end
)
653 if((*src
)->state
!= AL_PLAYING
)
655 --((*ctx
)->ActiveSourceCount
);
659 MixSource(*src
, *ctx
, DryBuffer
, SamplesToDo
,
660 device
->ClickRemoval
, device
->PendingClicks
);
664 /* effect slot processing */
665 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
667 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
669 ClickRemoval
= ALEffectSlot
->ClickRemoval
;
670 for(i
= 0;i
< SamplesToDo
;i
++)
672 ClickRemoval
[0] -= ClickRemoval
[0] / 256.0f
;
673 ALEffectSlot
->WetBuffer
[i
] += ClickRemoval
[0];
677 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
678 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
681 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
, SamplesToDo
, ALEffectSlot
->WetBuffer
, DryBuffer
);
683 for(i
= 0;i
< SamplesToDo
;i
++)
684 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
687 ProcessContext(*ctx
);
690 device
->SamplesPlayed
+= SamplesToDo
;
691 ProcessContext(NULL
);
693 //Post processing loop
694 ClickRemoval
= device
->ClickRemoval
;
695 for(i
= 0;i
< SamplesToDo
;i
++)
697 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
699 ClickRemoval
[c
] -= ClickRemoval
[c
] / 256.0f
;
700 DryBuffer
[i
][c
] += ClickRemoval
[c
];
703 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
705 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
706 device
->PendingClicks
[i
] = 0.0f
;
709 ChanMap
= device
->DevChannels
;
710 Matrix
= device
->ChannelMatrix
;
711 switch(device
->Format
)
713 #define CHECK_WRITE_FORMAT(bits, type, func) \
714 case AL_FORMAT_MONO##bits: \
715 for(i = 0;i < SamplesToDo;i++) \
718 for(c = 0;c < OUTPUTCHANNELS;c++) \
719 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
720 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
721 buffer = ((type*)buffer) + 1; \
724 case AL_FORMAT_STEREO##bits: \
727 for(i = 0;i < SamplesToDo;i++) \
729 float samples[2] = { 0.0f, 0.0f }; \
730 for(c = 0;c < OUTPUTCHANNELS;c++) \
732 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
733 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
735 bs2b_cross_feed(device->Bs2b, samples); \
736 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
737 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
738 buffer = ((type*)buffer) + 2; \
743 for(i = 0;i < SamplesToDo;i++) \
745 static const Channel chans[] = { \
746 FRONT_LEFT, FRONT_RIGHT \
748 for(j = 0;j < 2;j++) \
751 for(c = 0;c < OUTPUTCHANNELS;c++) \
752 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
753 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
755 buffer = ((type*)buffer) + 2; \
759 case AL_FORMAT_QUAD##bits: \
760 for(i = 0;i < SamplesToDo;i++) \
762 static const Channel chans[] = { \
763 FRONT_LEFT, FRONT_RIGHT, \
764 BACK_LEFT, BACK_RIGHT, \
766 for(j = 0;j < 4;j++) \
769 for(c = 0;c < OUTPUTCHANNELS;c++) \
770 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
771 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
773 buffer = ((type*)buffer) + 4; \
776 case AL_FORMAT_51CHN##bits: \
777 for(i = 0;i < SamplesToDo;i++) \
779 static const Channel chans[] = { \
780 FRONT_LEFT, FRONT_RIGHT, \
782 BACK_LEFT, BACK_RIGHT, \
784 for(j = 0;j < 6;j++) \
787 for(c = 0;c < OUTPUTCHANNELS;c++) \
788 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
789 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
791 buffer = ((type*)buffer) + 6; \
794 case AL_FORMAT_61CHN##bits: \
795 for(i = 0;i < SamplesToDo;i++) \
797 static const Channel chans[] = { \
798 FRONT_LEFT, FRONT_RIGHT, \
799 FRONT_CENTER, LFE, BACK_CENTER, \
800 SIDE_LEFT, SIDE_RIGHT, \
802 for(j = 0;j < 7;j++) \
805 for(c = 0;c < OUTPUTCHANNELS;c++) \
806 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
807 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
809 buffer = ((type*)buffer) + 7; \
812 case AL_FORMAT_71CHN##bits: \
813 for(i = 0;i < SamplesToDo;i++) \
815 static const Channel chans[] = { \
816 FRONT_LEFT, FRONT_RIGHT, \
818 BACK_LEFT, BACK_RIGHT, \
819 SIDE_LEFT, SIDE_RIGHT \
821 for(j = 0;j < 8;j++) \
824 for(c = 0;c < OUTPUTCHANNELS;c++) \
825 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
826 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
828 buffer = ((type*)buffer) + 8; \
832 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
833 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
834 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
835 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
836 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
837 #undef AL_FORMAT_STEREO32
838 #undef AL_FORMAT_MONO32
839 #undef CHECK_WRITE_FORMAT
848 #if defined(HAVE_FESETROUND)
849 fesetround(fpuState
);
850 #elif defined(HAVE__CONTROLFP)
851 _controlfp(fpuState
, 0xfffff);