Better protect against negative attenuation
[openal-soft.git] / Alc / mixer.c
blobecb60aadd152f850c745cf483abad61927d63f98
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.h"
40 static __inline ALfloat aluF2F(ALfloat Value)
42 return Value;
45 static __inline ALshort aluF2S(ALfloat Value)
47 ALint i;
49 if(Value <= -1.0f) i = -32768;
50 else if(Value >= 1.0f) i = 32767;
51 else i = (ALint)(Value*32767.5f - 0.5f);
53 return ((ALshort)i);
56 static __inline ALubyte aluF2UB(ALfloat Value)
58 ALshort i = aluF2S(Value);
59 return (i>>8)+128;
63 static __inline ALfloat point32(ALfloat val1, ALfloat val2, ALint frac)
65 return val1;
66 (void)val2;
67 (void)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;
82 (void)val2;
83 (void)frac;
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 { \
99 if(j == 0) \
101 value = sampler##S(Data.p##S[DataPosInt], Data.p##S[DataPosInt+1], \
102 DataPosFrac); \
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], \
124 DataPosFrac); \
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; \
147 j++; \
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]; \
172 } while(0)
174 #define DO_MIX_STEREO(S,sampler) do { \
175 const ALfloat scaler = 1.0f/Channels; \
176 if(j == 0) \
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], \
182 DataPosFrac); \
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], \
202 DataPosFrac); \
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; \
219 j++; \
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], \
230 frac); \
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; \
244 } while(0)
246 #define DO_MIX_MC(S,sampler) do { \
247 const ALfloat scaler = 1.0f/Channels; \
248 if(j == 0) \
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], \
254 DataPosFrac); \
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], \
272 DataPosFrac); \
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; \
287 j++; \
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], \
298 frac); \
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]; \
310 } while(0)
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: \
324 break; \
326 } while(0)
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 \
333 }; \
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: \
345 break; \
347 } while(0)
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: \
362 break; \
364 } while(0)
367 #define MIX(S) do { \
368 if(Channels == 1) /* Mono */ \
369 MIX_MONO(S); \
370 else if(Channels == 2) /* Stereo */ \
371 MIX_STEREO(S); \
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, \
377 FRONT_CENTER, LFE, \
378 BACK_LEFT, BACK_RIGHT); \
379 else if(Channels == 7) /* 6.1 */ \
380 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
381 FRONT_CENTER, LFE, \
382 BACK_CENTER, \
383 SIDE_LEFT, SIDE_RIGHT); \
384 else if(Channels == 8) /* 7.1 */ \
385 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
386 FRONT_CENTER, LFE, \
387 BACK_LEFT, BACK_RIGHT, \
388 SIDE_LEFT, SIDE_RIGHT); \
389 } while(0)
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];
402 ALuint i, j, out;
403 ALfloat value, outsamp;
404 ALbufferlistitem *BufferListItem;
405 ALint64 DataSize64,DataPos64;
406 FILTER *DryFilter, *WetFilter[MAX_SENDS];
407 ALfloat WetSend[MAX_SENDS];
408 ALint increment;
409 ALuint DataPosInt, DataPosFrac;
410 ALuint BuffersPlayed;
411 ALboolean Looping;
412 ALenum State;
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;
445 else
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;
458 j = 0;
459 do {
460 const ALbuffer *ALBuffer;
461 union {
462 ALfloat *p32;
463 ALshort *p16;
464 ALubyte *p8;
465 } Data = { NULL };
466 ALuint DataSize = 0;
467 ALuint LoopStart = 0;
468 ALuint LoopEnd = 0;
469 ALuint Channels, Bytes;
470 ALuint BufferSize;
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);
481 LoopStart = 0;
482 LoopEnd = DataSize;
483 if(Looping && Source->lSourceType == AL_STATIC)
485 /* If current pos is beyond the loop range, do not loop */
486 if(DataPosInt >= LoopEnd)
487 Looping = AL_FALSE;
488 else
490 LoopStart = ALBuffer->LoopStart;
491 LoopEnd = ALBuffer->LoopEnd;
496 if(DataPosInt >= DataSize)
497 goto skipmix;
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);
510 else if(Looping)
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],
519 ulExtraSamples);
522 else
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 */
536 MIX(32);
537 else if(Bytes == 2) /* signed 16-bit */
538 MIX(16);
540 skipmix:
541 /* Handle looping sources */
542 if(DataPosInt >= LoopEnd)
544 if(BuffersPlayed < (Source->BuffersInQueue-1))
546 BufferListItem = BufferListItem->next;
547 BuffersPlayed++;
548 DataPosInt -= DataSize;
550 else if(Looping)
552 BufferListItem = Source->queue;
553 BuffersPlayed = 0;
554 if(Source->lSourceType == AL_STATIC)
555 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
556 else
557 DataPosInt -= DataSize;
559 else
561 State = AL_STOPPED;
562 BufferListItem = Source->queue;
563 BuffersPlayed = Source->BuffersInQueue;
564 DataPosInt = 0;
565 DataPosFrac = 0;
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;
578 #undef DO_MIX_MC
579 #undef DO_MIX_STEREO
580 #undef DO_MIX_MONO
582 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
584 ALfloat (*DryBuffer)[OUTPUTCHANNELS];
585 ALfloat (*Matrix)[OUTPUTCHANNELS];
586 ALfloat *ClickRemoval;
587 const ALuint *ChanMap;
588 ALuint SamplesToDo;
589 ALeffectslot *ALEffectSlot;
590 ALCcontext **ctx, **ctx_end;
591 ALsource **src, **src_end;
592 ALfloat samp;
593 int fpuState;
594 ALuint i, j, c;
595 ALsizei e;
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);
603 #else
604 (void)fpuState;
605 #endif
607 DryBuffer = device->DryBuffer;
608 while(size > 0)
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);
630 *src = *(--src_end);
631 continue;
633 MixSource(*src, *ctx, DryBuffer, SamplesToDo,
634 device->ClickRemoval, device->PendingClicks);
635 src++;
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];
649 for(i = 0;i < 1;i++)
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);
662 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++) \
691 samp = 0.0f; \
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; \
697 break; \
698 case AL_FORMAT_STEREO##bits: \
699 if(device->Bs2b) \
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; \
715 else \
717 for(i = 0;i < SamplesToDo;i++) \
719 static const Channel chans[] = { \
720 FRONT_LEFT, FRONT_RIGHT \
721 }; \
722 for(j = 0;j < 2;j++) \
724 samp = 0.0f; \
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; \
732 break; \
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, \
739 }; \
740 for(j = 0;j < 4;j++) \
742 samp = 0.0f; \
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; \
749 break; \
750 case AL_FORMAT_51CHN##bits: \
751 for(i = 0;i < SamplesToDo;i++) \
753 static const Channel chans[] = { \
754 FRONT_LEFT, FRONT_RIGHT, \
755 FRONT_CENTER, LFE, \
756 BACK_LEFT, BACK_RIGHT, \
757 }; \
758 for(j = 0;j < 6;j++) \
760 samp = 0.0f; \
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; \
767 break; \
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, \
775 }; \
776 for(j = 0;j < 7;j++) \
778 samp = 0.0f; \
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; \
785 break; \
786 case AL_FORMAT_71CHN##bits: \
787 for(i = 0;i < SamplesToDo;i++) \
789 static const Channel chans[] = { \
790 FRONT_LEFT, FRONT_RIGHT, \
791 FRONT_CENTER, LFE, \
792 BACK_LEFT, BACK_RIGHT, \
793 SIDE_LEFT, SIDE_RIGHT \
794 }; \
795 for(j = 0;j < 8;j++) \
797 samp = 0.0f; \
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; \
804 break;
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
815 default:
816 break;
819 size -= SamplesToDo;
822 #if defined(HAVE_FESETROUND)
823 fesetround(fpuState);
824 #elif defined(HAVE__CONTROLFP)
825 _controlfp(fpuState, 0xfffff);
826 #endif