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.5f
- 0.5f
);
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
+0.5f
) / 32767.5f
;
85 static __inline ALfloat
lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
87 val1
+= ((val2
-val1
)*(frac
* (1.0f
/(1<<FRACTIONBITS
))));
88 return (val1
+0.5f
) / 32767.5f
;
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
+0.5f
) / 32767.5f
;
98 #define DO_MIX_MONO(S,sampler) do { \
101 value = sampler##S(Data.p##S[DataPosInt], Data.p##S[DataPosInt+1], \
104 outsamp = lpFilter4PC(DryFilter, 0, value); \
105 ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \
106 ClickRemoval[FRONT_RIGHT] -= outsamp*DrySend[FRONT_RIGHT]; \
107 ClickRemoval[SIDE_LEFT] -= outsamp*DrySend[SIDE_LEFT]; \
108 ClickRemoval[SIDE_RIGHT] -= outsamp*DrySend[SIDE_RIGHT]; \
109 ClickRemoval[BACK_LEFT] -= outsamp*DrySend[BACK_LEFT]; \
110 ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \
111 ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \
112 ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \
114 for(out = 0;out < MAX_SENDS;out++) \
116 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
117 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
120 while(BufferSize--) \
122 /* First order interpolator */ \
123 value = sampler##S(Data.p##S[DataPosInt], Data.p##S[DataPosInt+1], \
126 /* Direct path final mix buffer and panning */ \
127 outsamp = lpFilter4P(DryFilter, 0, value); \
128 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
129 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
130 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
131 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
132 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
133 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
134 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
135 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
137 /* Room path final mix buffer and panning */ \
138 for(out = 0;out < MAX_SENDS;out++) \
140 outsamp = lpFilter2P(WetFilter[out], 0, value); \
141 WetBuffer[out][j] += outsamp*WetSend[out]; \
144 DataPosFrac += increment; \
145 DataPosInt += DataPosFrac>>FRACTIONBITS; \
146 DataPosFrac &= FRACTIONMASK; \
149 if(j == SamplesToDo) \
151 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
152 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
153 ((DataPosFrac-increment)&FRACTIONMASK)); \
154 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
156 outsamp = lpFilter4PC(DryFilter, 0, value); \
157 PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
158 PendingClicks[FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
159 PendingClicks[SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
160 PendingClicks[SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
161 PendingClicks[BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
162 PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
163 PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
164 PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
166 for(out = 0;out < MAX_SENDS;out++) \
168 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
169 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
174 #define DO_MIX_STEREO(S,sampler) do { \
175 const ALfloat scaler = 1.0f/Channels; \
178 for(i = 0;i < Channels;i++) \
180 value = sampler##S(Data.p##S[DataPosInt*Channels + i], \
181 Data.p##S[(DataPosInt+1)*Channels + i], \
184 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
185 ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \
186 ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \
187 ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \
189 for(out = 0;out < MAX_SENDS;out++) \
191 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
192 WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \
196 while(BufferSize--) \
198 for(i = 0;i < Channels;i++) \
200 value = sampler##S(Data.p##S[DataPosInt*Channels + i], \
201 Data.p##S[(DataPosInt+1)*Channels + i], \
204 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
205 DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
206 DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
207 DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
209 for(out = 0;out < MAX_SENDS;out++) \
211 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
212 WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \
216 DataPosFrac += increment; \
217 DataPosInt += DataPosFrac>>FRACTIONBITS; \
218 DataPosFrac &= FRACTIONMASK; \
221 if(j == SamplesToDo) \
223 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
224 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
225 ((DataPosFrac-increment)&FRACTIONMASK)); \
226 for(i = 0;i < Channels;i++) \
228 value = sampler##S(Data.p##S[pos*Channels + i], \
229 Data.p##S[(pos+1)*Channels + i], \
232 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
233 PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
234 PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
235 PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
237 for(out = 0;out < MAX_SENDS;out++) \
239 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
240 WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \
246 #define DO_MIX_MC(S,sampler) do { \
247 const ALfloat scaler = 1.0f/Channels; \
250 for(i = 0;i < Channels;i++) \
252 value = sampler##S(Data.p##S[DataPosInt*Channels + i], \
253 Data.p##S[(DataPosInt+1)*Channels + i], \
256 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
257 ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \
259 for(out = 0;out < MAX_SENDS;out++) \
261 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
262 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
266 while(BufferSize--) \
268 for(i = 0;i < Channels;i++) \
270 value = sampler##S(Data.p##S[DataPosInt*Channels + i], \
271 Data.p##S[(DataPosInt+1)*Channels + i], \
274 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
275 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
277 for(out = 0;out < MAX_SENDS;out++) \
279 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
280 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
284 DataPosFrac += increment; \
285 DataPosInt += DataPosFrac>>FRACTIONBITS; \
286 DataPosFrac &= FRACTIONMASK; \
289 if(j == SamplesToDo) \
291 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
292 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
293 ((DataPosFrac-increment)&FRACTIONMASK)); \
294 for(i = 0;i < Channels;i++) \
296 value = sampler##S(Data.p##S[pos*Channels + i], \
297 Data.p##S[(pos+1)*Channels + i], \
300 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
301 PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \
303 for(out = 0;out < MAX_SENDS;out++) \
305 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
306 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
313 #define MIX_MONO(S) do { \
316 case POINT_RESAMPLER: \
317 DO_MIX_MONO(S,point); break; \
318 case LINEAR_RESAMPLER: \
319 DO_MIX_MONO(S,lerp); break; \
320 case COSINE_RESAMPLER: \
321 DO_MIX_MONO(S,cos_lerp); break; \
322 case RESAMPLER_MIN: \
323 case RESAMPLER_MAX: \
328 #define MIX_STEREO(S) do { \
329 const int chans[] = { \
330 FRONT_LEFT, FRONT_RIGHT, \
331 SIDE_LEFT, SIDE_RIGHT, \
332 BACK_LEFT, BACK_RIGHT \
337 case POINT_RESAMPLER: \
338 DO_MIX_STEREO(S,point); break; \
339 case LINEAR_RESAMPLER: \
340 DO_MIX_STEREO(S,lerp); break; \
341 case COSINE_RESAMPLER: \
342 DO_MIX_STEREO(S,cos_lerp); break; \
343 case RESAMPLER_MIN: \
344 case RESAMPLER_MAX: \
349 #define MIX_MC(S,...) do { \
350 const int chans[] = { __VA_ARGS__ }; \
354 case POINT_RESAMPLER: \
355 DO_MIX_MC(S,point); break; \
356 case LINEAR_RESAMPLER: \
357 DO_MIX_MC(S,lerp); break; \
358 case COSINE_RESAMPLER: \
359 DO_MIX_MC(S,cos_lerp); break; \
360 case RESAMPLER_MIN: \
361 case RESAMPLER_MAX: \
367 #define MIX(S) do { \
368 if(Channels == 1) /* Mono */ \
370 else if(Channels == 2) /* Stereo */ \
372 else if(Channels == 4) /* Quad */ \
373 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
374 BACK_LEFT, BACK_RIGHT); \
375 else if(Channels == 6) /* 5.1 */ \
376 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
378 BACK_LEFT, BACK_RIGHT); \
379 else if(Channels == 7) /* 6.1 */ \
380 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
383 SIDE_LEFT, SIDE_RIGHT); \
384 else if(Channels == 8) /* 7.1 */ \
385 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
387 BACK_LEFT, BACK_RIGHT, \
388 SIDE_LEFT, SIDE_RIGHT); \
392 static void MixSource(ALsource
*ALSource
, ALCcontext
*ALContext
,
393 float (*DryBuffer
)[OUTPUTCHANNELS
], ALuint SamplesToDo
,
394 ALfloat
*ClickRemoval
, ALfloat
*PendingClicks
)
396 static float DummyBuffer
[BUFFERSIZE
];
397 static ALfloat DummyClickRemoval
[OUTPUTCHANNELS
];
398 ALfloat
*WetBuffer
[MAX_SENDS
];
399 ALfloat DrySend
[OUTPUTCHANNELS
];
400 ALfloat
*WetClickRemoval
[MAX_SENDS
];
401 ALfloat
*WetPendingClicks
[MAX_SENDS
];
403 ALfloat value
, outsamp
;
404 ALbufferlistitem
*BufferListItem
;
405 ALint64 DataSize64
,DataPos64
;
406 FILTER
*DryFilter
, *WetFilter
[MAX_SENDS
];
407 ALfloat WetSend
[MAX_SENDS
];
409 ALuint DataPosInt
, DataPosFrac
;
410 resampler_t Resampler
;
411 ALuint BuffersPlayed
;
415 if(ALSource
->NeedsUpdate
)
417 ALsource_Update(ALSource
, ALContext
);
418 ALSource
->NeedsUpdate
= AL_FALSE
;
421 /* Get source info */
422 Resampler
= ALSource
->Resampler
;
423 State
= ALSource
->state
;
424 BuffersPlayed
= ALSource
->BuffersPlayed
;
425 DataPosInt
= ALSource
->position
;
426 DataPosFrac
= ALSource
->position_fraction
;
427 Looping
= ALSource
->bLooping
;
429 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
430 DrySend
[i
] = ALSource
->Params
.DryGains
[i
];
431 for(i
= 0;i
< MAX_SENDS
;i
++)
432 WetSend
[i
] = ALSource
->Params
.WetGains
[i
];
434 /* Get fixed point step */
435 increment
= ALSource
->Params
.Step
;
437 DryFilter
= &ALSource
->Params
.iirFilter
;
438 for(i
= 0;i
< MAX_SENDS
;i
++)
440 WetFilter
[i
] = &ALSource
->Params
.Send
[i
].iirFilter
;
441 if(ALSource
->Send
[i
].Slot
)
443 WetBuffer
[i
] = ALSource
->Send
[i
].Slot
->WetBuffer
;
444 WetClickRemoval
[i
] = ALSource
->Send
[i
].Slot
->ClickRemoval
;
445 WetPendingClicks
[i
] = ALSource
->Send
[i
].Slot
->PendingClicks
;
449 WetBuffer
[i
] = DummyBuffer
;
450 WetClickRemoval
[i
] = DummyClickRemoval
;
451 WetPendingClicks
[i
] = DummyClickRemoval
;
455 /* Get current buffer queue item */
456 BufferListItem
= ALSource
->queue
;
457 for(i
= 0;i
< BuffersPlayed
;i
++)
458 BufferListItem
= BufferListItem
->next
;
462 const ALbuffer
*ALBuffer
;
469 ALuint LoopStart
= 0;
471 ALuint Channels
, Bytes
;
474 /* Get buffer info */
475 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
477 Data
.p8
= ALBuffer
->data
;
478 DataSize
= ALBuffer
->size
;
479 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
480 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
481 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
485 if(Looping
&& ALSource
->lSourceType
== AL_STATIC
)
487 /* If current pos is beyond the loop range, do not loop */
488 if(DataPosInt
>= LoopEnd
)
492 LoopStart
= ALBuffer
->LoopStart
;
493 LoopEnd
= ALBuffer
->LoopEnd
;
498 if(DataPosInt
>= DataSize
)
501 if(BufferListItem
->next
)
503 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
504 if(NextBuf
&& NextBuf
->size
)
506 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
507 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
508 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
509 NextBuf
->data
, ulExtraSamples
);
514 ALbuffer
*NextBuf
= ALSource
->queue
->buffer
;
515 if(NextBuf
&& NextBuf
->size
)
517 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
518 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
519 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
520 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
525 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
527 /* Figure out how many samples we can mix. */
528 DataSize64
= LoopEnd
;
529 DataSize64
<<= FRACTIONBITS
;
530 DataPos64
= DataPosInt
;
531 DataPos64
<<= FRACTIONBITS
;
532 DataPos64
+= DataPosFrac
;
533 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
535 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
537 if(Bytes
== 4) /* 32-bit float */
539 else if(Bytes
== 2) /* signed 16-bit */
543 /* Handle looping sources */
544 if(DataPosInt
>= LoopEnd
)
546 if(BuffersPlayed
< (ALSource
->BuffersInQueue
-1))
548 BufferListItem
= BufferListItem
->next
;
550 DataPosInt
-= DataSize
;
554 BufferListItem
= ALSource
->queue
;
556 if(ALSource
->lSourceType
== AL_STATIC
)
557 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
559 DataPosInt
-= DataSize
;
564 BufferListItem
= ALSource
->queue
;
565 BuffersPlayed
= ALSource
->BuffersInQueue
;
570 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
572 /* Update source info */
573 ALSource
->state
= State
;
574 ALSource
->BuffersPlayed
= BuffersPlayed
;
575 ALSource
->position
= DataPosInt
;
576 ALSource
->position_fraction
= DataPosFrac
;
577 ALSource
->Buffer
= BufferListItem
->buffer
;
584 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
586 float (*DryBuffer
)[OUTPUTCHANNELS
];
587 ALfloat (*Matrix
)[OUTPUTCHANNELS
];
588 ALfloat
*ClickRemoval
;
589 const ALuint
*ChanMap
;
591 ALeffectslot
*ALEffectSlot
;
592 ALCcontext
**ctx
, **ctx_end
;
593 ALsource
**src
, **src_end
;
599 #if defined(HAVE_FESETROUND)
600 fpuState
= fegetround();
601 fesetround(FE_TOWARDZERO
);
602 #elif defined(HAVE__CONTROLFP)
603 fpuState
= _controlfp(0, 0);
604 _controlfp(_RC_CHOP
, _MCW_RC
);
609 DryBuffer
= device
->DryBuffer
;
612 /* Setup variables */
613 SamplesToDo
= min(size
, BUFFERSIZE
);
615 /* Clear mixing buffer */
616 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
618 SuspendContext(NULL
);
619 ctx
= device
->Contexts
;
620 ctx_end
= ctx
+ device
->NumContexts
;
621 while(ctx
!= ctx_end
)
623 SuspendContext(*ctx
);
625 src
= (*ctx
)->ActiveSources
;
626 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
627 while(src
!= src_end
)
629 if((*src
)->state
!= AL_PLAYING
)
631 --((*ctx
)->ActiveSourceCount
);
635 MixSource(*src
, *ctx
, DryBuffer
, SamplesToDo
,
636 device
->ClickRemoval
, device
->PendingClicks
);
640 /* effect slot processing */
641 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
643 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
645 ClickRemoval
= ALEffectSlot
->ClickRemoval
;
646 for(i
= 0;i
< SamplesToDo
;i
++)
648 ClickRemoval
[0] -= ClickRemoval
[0] / 256.0f
;
649 ALEffectSlot
->WetBuffer
[i
] += ClickRemoval
[0];
653 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
654 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
657 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
, SamplesToDo
, ALEffectSlot
->WetBuffer
, DryBuffer
);
659 for(i
= 0;i
< SamplesToDo
;i
++)
660 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
663 ProcessContext(*ctx
);
666 device
->SamplesPlayed
+= SamplesToDo
;
667 ProcessContext(NULL
);
669 //Post processing loop
670 ClickRemoval
= device
->ClickRemoval
;
671 for(i
= 0;i
< SamplesToDo
;i
++)
673 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
675 ClickRemoval
[c
] -= ClickRemoval
[c
] / 256.0f
;
676 DryBuffer
[i
][c
] += ClickRemoval
[c
];
679 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
681 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
682 device
->PendingClicks
[i
] = 0.0f
;
685 ChanMap
= device
->DevChannels
;
686 Matrix
= device
->ChannelMatrix
;
687 switch(device
->Format
)
689 #define CHECK_WRITE_FORMAT(bits, type, func) \
690 case AL_FORMAT_MONO##bits: \
691 for(i = 0;i < SamplesToDo;i++) \
694 for(c = 0;c < OUTPUTCHANNELS;c++) \
695 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
696 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
697 buffer = ((type*)buffer) + 1; \
700 case AL_FORMAT_STEREO##bits: \
703 for(i = 0;i < SamplesToDo;i++) \
705 float samples[2] = { 0.0f, 0.0f }; \
706 for(c = 0;c < OUTPUTCHANNELS;c++) \
708 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
709 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
711 bs2b_cross_feed(device->Bs2b, samples); \
712 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
713 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
714 buffer = ((type*)buffer) + 2; \
719 for(i = 0;i < SamplesToDo;i++) \
721 static const Channel chans[] = { \
722 FRONT_LEFT, FRONT_RIGHT \
724 for(j = 0;j < 2;j++) \
727 for(c = 0;c < OUTPUTCHANNELS;c++) \
728 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
729 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
731 buffer = ((type*)buffer) + 2; \
735 case AL_FORMAT_QUAD##bits: \
736 for(i = 0;i < SamplesToDo;i++) \
738 static const Channel chans[] = { \
739 FRONT_LEFT, FRONT_RIGHT, \
740 BACK_LEFT, BACK_RIGHT, \
742 for(j = 0;j < 4;j++) \
745 for(c = 0;c < OUTPUTCHANNELS;c++) \
746 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
747 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
749 buffer = ((type*)buffer) + 4; \
752 case AL_FORMAT_51CHN##bits: \
753 for(i = 0;i < SamplesToDo;i++) \
755 static const Channel chans[] = { \
756 FRONT_LEFT, FRONT_RIGHT, \
758 BACK_LEFT, BACK_RIGHT, \
760 for(j = 0;j < 6;j++) \
763 for(c = 0;c < OUTPUTCHANNELS;c++) \
764 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
765 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
767 buffer = ((type*)buffer) + 6; \
770 case AL_FORMAT_61CHN##bits: \
771 for(i = 0;i < SamplesToDo;i++) \
773 static const Channel chans[] = { \
774 FRONT_LEFT, FRONT_RIGHT, \
775 FRONT_CENTER, LFE, BACK_CENTER, \
776 SIDE_LEFT, SIDE_RIGHT, \
778 for(j = 0;j < 7;j++) \
781 for(c = 0;c < OUTPUTCHANNELS;c++) \
782 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
783 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
785 buffer = ((type*)buffer) + 7; \
788 case AL_FORMAT_71CHN##bits: \
789 for(i = 0;i < SamplesToDo;i++) \
791 static const Channel chans[] = { \
792 FRONT_LEFT, FRONT_RIGHT, \
794 BACK_LEFT, BACK_RIGHT, \
795 SIDE_LEFT, SIDE_RIGHT \
797 for(j = 0;j < 8;j++) \
800 for(c = 0;c < OUTPUTCHANNELS;c++) \
801 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
802 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
804 buffer = ((type*)buffer) + 8; \
808 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
809 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
810 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
811 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
812 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
813 #undef AL_FORMAT_STEREO32
814 #undef AL_FORMAT_MONO32
815 #undef CHECK_WRITE_FORMAT
824 #if defined(HAVE_FESETROUND)
825 fesetround(fpuState
);
826 #elif defined(HAVE__CONTROLFP)
827 _controlfp(fpuState
, 0xfffff);