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 { \
314 switch(Source->Resampler) \
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 \
335 switch(Source->Resampler) \
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__ }; \
352 switch(Source->Resampler) \
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
*Source
, ALCcontext
*Context
,
393 ALfloat (*DryBuffer
)[OUTPUTCHANNELS
], ALuint SamplesToDo
,
394 ALfloat
*ClickRemoval
, ALfloat
*PendingClicks
)
396 static ALfloat 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 ALuint BuffersPlayed
;
414 if(Source
->NeedsUpdate
)
416 ALsource_Update(Source
, Context
);
417 Source
->NeedsUpdate
= AL_FALSE
;
420 /* Get source info */
421 State
= Source
->state
;
422 BuffersPlayed
= Source
->BuffersPlayed
;
423 DataPosInt
= Source
->position
;
424 DataPosFrac
= Source
->position_fraction
;
425 Looping
= Source
->bLooping
;
427 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
428 DrySend
[i
] = Source
->Params
.DryGains
[i
];
429 for(i
= 0;i
< MAX_SENDS
;i
++)
430 WetSend
[i
] = Source
->Params
.WetGains
[i
];
432 /* Get fixed point step */
433 increment
= Source
->Params
.Step
;
435 DryFilter
= &Source
->Params
.iirFilter
;
436 for(i
= 0;i
< MAX_SENDS
;i
++)
438 WetFilter
[i
] = &Source
->Params
.Send
[i
].iirFilter
;
439 if(Source
->Send
[i
].Slot
)
441 WetBuffer
[i
] = Source
->Send
[i
].Slot
->WetBuffer
;
442 WetClickRemoval
[i
] = Source
->Send
[i
].Slot
->ClickRemoval
;
443 WetPendingClicks
[i
] = Source
->Send
[i
].Slot
->PendingClicks
;
447 WetBuffer
[i
] = DummyBuffer
;
448 WetClickRemoval
[i
] = DummyClickRemoval
;
449 WetPendingClicks
[i
] = DummyClickRemoval
;
453 /* Get current buffer queue item */
454 BufferListItem
= Source
->queue
;
455 for(i
= 0;i
< BuffersPlayed
;i
++)
456 BufferListItem
= BufferListItem
->next
;
460 const ALbuffer
*ALBuffer
;
467 ALuint LoopStart
= 0;
469 ALuint Channels
, Bytes
;
472 /* Get buffer info */
473 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
475 Data
.p8
= ALBuffer
->data
;
476 DataSize
= ALBuffer
->size
;
477 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
478 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
479 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
483 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
485 /* If current pos is beyond the loop range, do not loop */
486 if(DataPosInt
>= LoopEnd
)
490 LoopStart
= ALBuffer
->LoopStart
;
491 LoopEnd
= ALBuffer
->LoopEnd
;
496 if(DataPosInt
>= DataSize
)
499 if(BufferListItem
->next
)
501 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
502 if(NextBuf
&& NextBuf
->size
)
504 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
505 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
506 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
507 NextBuf
->data
, ulExtraSamples
);
512 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
513 if(NextBuf
&& NextBuf
->size
)
515 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
516 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
517 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
518 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
523 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, (BUFFER_PADDING
*Channels
*Bytes
));
525 /* Figure out how many samples we can mix. */
526 DataSize64
= LoopEnd
;
527 DataSize64
<<= FRACTIONBITS
;
528 DataPos64
= DataPosInt
;
529 DataPos64
<<= FRACTIONBITS
;
530 DataPos64
+= DataPosFrac
;
531 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
533 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
535 if(Bytes
== 4) /* 32-bit float */
537 else if(Bytes
== 2) /* signed 16-bit */
541 /* Handle looping sources */
542 if(DataPosInt
>= LoopEnd
)
544 if(BuffersPlayed
< (Source
->BuffersInQueue
-1))
546 BufferListItem
= BufferListItem
->next
;
548 DataPosInt
-= DataSize
;
552 BufferListItem
= Source
->queue
;
554 if(Source
->lSourceType
== AL_STATIC
)
555 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
557 DataPosInt
-= DataSize
;
562 BufferListItem
= Source
->queue
;
563 BuffersPlayed
= Source
->BuffersInQueue
;
568 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
570 /* Update source info */
571 Source
->state
= State
;
572 Source
->BuffersPlayed
= BuffersPlayed
;
573 Source
->position
= DataPosInt
;
574 Source
->position_fraction
= DataPosFrac
;
575 Source
->Buffer
= BufferListItem
->buffer
;
582 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
584 ALfloat (*DryBuffer
)[OUTPUTCHANNELS
];
585 ALfloat (*Matrix
)[OUTPUTCHANNELS
];
586 ALfloat
*ClickRemoval
;
587 const ALuint
*ChanMap
;
589 ALeffectslot
*ALEffectSlot
;
590 ALCcontext
**ctx
, **ctx_end
;
591 ALsource
**src
, **src_end
;
597 #if defined(HAVE_FESETROUND)
598 fpuState
= fegetround();
599 fesetround(FE_TOWARDZERO
);
600 #elif defined(HAVE__CONTROLFP)
601 fpuState
= _controlfp(0, 0);
602 _controlfp(_RC_CHOP
, _MCW_RC
);
607 DryBuffer
= device
->DryBuffer
;
610 /* Setup variables */
611 SamplesToDo
= min(size
, BUFFERSIZE
);
613 /* Clear mixing buffer */
614 memset(DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
616 SuspendContext(NULL
);
617 ctx
= device
->Contexts
;
618 ctx_end
= ctx
+ device
->NumContexts
;
619 while(ctx
!= ctx_end
)
621 SuspendContext(*ctx
);
623 src
= (*ctx
)->ActiveSources
;
624 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
625 while(src
!= src_end
)
627 if((*src
)->state
!= AL_PLAYING
)
629 --((*ctx
)->ActiveSourceCount
);
633 MixSource(*src
, *ctx
, DryBuffer
, SamplesToDo
,
634 device
->ClickRemoval
, device
->PendingClicks
);
638 /* effect slot processing */
639 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
641 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
643 ClickRemoval
= ALEffectSlot
->ClickRemoval
;
644 for(i
= 0;i
< SamplesToDo
;i
++)
646 ClickRemoval
[0] -= ClickRemoval
[0] / 256.0f
;
647 ALEffectSlot
->WetBuffer
[i
] += ClickRemoval
[0];
651 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
652 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
655 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
, SamplesToDo
, ALEffectSlot
->WetBuffer
, DryBuffer
);
657 for(i
= 0;i
< SamplesToDo
;i
++)
658 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
661 ProcessContext(*ctx
);
664 device
->SamplesPlayed
+= SamplesToDo
;
665 ProcessContext(NULL
);
667 //Post processing loop
668 ClickRemoval
= device
->ClickRemoval
;
669 for(i
= 0;i
< SamplesToDo
;i
++)
671 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
673 ClickRemoval
[c
] -= ClickRemoval
[c
] / 256.0f
;
674 DryBuffer
[i
][c
] += ClickRemoval
[c
];
677 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
679 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
680 device
->PendingClicks
[i
] = 0.0f
;
683 ChanMap
= device
->DevChannels
;
684 Matrix
= device
->ChannelMatrix
;
685 switch(device
->Format
)
687 #define CHECK_WRITE_FORMAT(bits, type, func) \
688 case AL_FORMAT_MONO##bits: \
689 for(i = 0;i < SamplesToDo;i++) \
692 for(c = 0;c < OUTPUTCHANNELS;c++) \
693 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
694 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
695 buffer = ((type*)buffer) + 1; \
698 case AL_FORMAT_STEREO##bits: \
701 for(i = 0;i < SamplesToDo;i++) \
703 float samples[2] = { 0.0f, 0.0f }; \
704 for(c = 0;c < OUTPUTCHANNELS;c++) \
706 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
707 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
709 bs2b_cross_feed(device->Bs2b, samples); \
710 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
711 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
712 buffer = ((type*)buffer) + 2; \
717 for(i = 0;i < SamplesToDo;i++) \
719 static const Channel chans[] = { \
720 FRONT_LEFT, FRONT_RIGHT \
722 for(j = 0;j < 2;j++) \
725 for(c = 0;c < OUTPUTCHANNELS;c++) \
726 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
727 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
729 buffer = ((type*)buffer) + 2; \
733 case AL_FORMAT_QUAD##bits: \
734 for(i = 0;i < SamplesToDo;i++) \
736 static const Channel chans[] = { \
737 FRONT_LEFT, FRONT_RIGHT, \
738 BACK_LEFT, BACK_RIGHT, \
740 for(j = 0;j < 4;j++) \
743 for(c = 0;c < OUTPUTCHANNELS;c++) \
744 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
745 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
747 buffer = ((type*)buffer) + 4; \
750 case AL_FORMAT_51CHN##bits: \
751 for(i = 0;i < SamplesToDo;i++) \
753 static const Channel chans[] = { \
754 FRONT_LEFT, FRONT_RIGHT, \
756 BACK_LEFT, BACK_RIGHT, \
758 for(j = 0;j < 6;j++) \
761 for(c = 0;c < OUTPUTCHANNELS;c++) \
762 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
763 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
765 buffer = ((type*)buffer) + 6; \
768 case AL_FORMAT_61CHN##bits: \
769 for(i = 0;i < SamplesToDo;i++) \
771 static const Channel chans[] = { \
772 FRONT_LEFT, FRONT_RIGHT, \
773 FRONT_CENTER, LFE, BACK_CENTER, \
774 SIDE_LEFT, SIDE_RIGHT, \
776 for(j = 0;j < 7;j++) \
779 for(c = 0;c < OUTPUTCHANNELS;c++) \
780 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
781 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
783 buffer = ((type*)buffer) + 7; \
786 case AL_FORMAT_71CHN##bits: \
787 for(i = 0;i < SamplesToDo;i++) \
789 static const Channel chans[] = { \
790 FRONT_LEFT, FRONT_RIGHT, \
792 BACK_LEFT, BACK_RIGHT, \
793 SIDE_LEFT, SIDE_RIGHT \
795 for(j = 0;j < 8;j++) \
798 for(c = 0;c < OUTPUTCHANNELS;c++) \
799 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
800 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
802 buffer = ((type*)buffer) + 8; \
806 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
807 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
808 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
809 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
810 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
811 #undef AL_FORMAT_STEREO32
812 #undef AL_FORMAT_MONO32
813 #undef CHECK_WRITE_FORMAT
822 #if defined(HAVE_FESETROUND)
823 fesetround(fpuState
);
824 #elif defined(HAVE__CONTROLFP)
825 _controlfp(fpuState
, 0xfffff);