Be consistent with a variable's use
[openal-soft.git] / Alc / mixer.c
blob11365e63f49623bd4c4850be7e643db9d440c26e
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(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(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(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 *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];
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 resampler_t Resampler;
411 ALuint BuffersPlayed;
412 ALboolean Looping;
413 ALenum State;
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;
447 else
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;
460 j = 0;
461 do {
462 const ALbuffer *ALBuffer;
463 union {
464 ALfloat *p32;
465 ALshort *p16;
466 ALubyte *p8;
467 } Data = { NULL };
468 ALuint DataSize = 0;
469 ALuint LoopStart = 0;
470 ALuint LoopEnd = 0;
471 ALuint Channels, Bytes;
472 ALuint BufferSize;
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);
483 LoopStart = 0;
484 LoopEnd = DataSize;
485 if(Looping && ALSource->lSourceType == AL_STATIC)
487 /* If current pos is beyond the loop range, do not loop */
488 if(DataPosInt >= LoopEnd)
489 Looping = AL_FALSE;
490 else
492 LoopStart = ALBuffer->LoopStart;
493 LoopEnd = ALBuffer->LoopEnd;
498 if(DataPosInt >= DataSize)
499 goto skipmix;
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);
512 else if(Looping)
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],
521 ulExtraSamples);
524 else
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 */
538 MIX(32);
539 else if(Bytes == 2) /* signed 16-bit */
540 MIX(16);
542 skipmix:
543 /* Handle looping sources */
544 if(DataPosInt >= LoopEnd)
546 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
548 BufferListItem = BufferListItem->next;
549 BuffersPlayed++;
550 DataPosInt -= DataSize;
552 else if(Looping)
554 BufferListItem = ALSource->queue;
555 BuffersPlayed = 0;
556 if(ALSource->lSourceType == AL_STATIC)
557 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
558 else
559 DataPosInt -= DataSize;
561 else
563 State = AL_STOPPED;
564 BufferListItem = ALSource->queue;
565 BuffersPlayed = ALSource->BuffersInQueue;
566 DataPosInt = 0;
567 DataPosFrac = 0;
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;
580 #undef DO_MIX_MC
581 #undef DO_MIX_STEREO
582 #undef DO_MIX_MONO
584 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
586 float (*DryBuffer)[OUTPUTCHANNELS];
587 ALfloat (*Matrix)[OUTPUTCHANNELS];
588 ALfloat *ClickRemoval;
589 const ALuint *ChanMap;
590 ALuint SamplesToDo;
591 ALeffectslot *ALEffectSlot;
592 ALCcontext **ctx, **ctx_end;
593 ALsource **src, **src_end;
594 ALfloat samp;
595 int fpuState;
596 ALuint i, j, c;
597 ALsizei e;
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);
605 #else
606 (void)fpuState;
607 #endif
609 DryBuffer = device->DryBuffer;
610 while(size > 0)
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);
632 *src = *(--src_end);
633 continue;
635 MixSource(*src, *ctx, DryBuffer, SamplesToDo,
636 device->ClickRemoval, device->PendingClicks);
637 src++;
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];
651 for(i = 0;i < 1;i++)
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);
664 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++) \
693 samp = 0.0f; \
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; \
699 break; \
700 case AL_FORMAT_STEREO##bits: \
701 if(device->Bs2b) \
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; \
717 else \
719 for(i = 0;i < SamplesToDo;i++) \
721 static const Channel chans[] = { \
722 FRONT_LEFT, FRONT_RIGHT \
723 }; \
724 for(j = 0;j < 2;j++) \
726 samp = 0.0f; \
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; \
734 break; \
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, \
741 }; \
742 for(j = 0;j < 4;j++) \
744 samp = 0.0f; \
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; \
751 break; \
752 case AL_FORMAT_51CHN##bits: \
753 for(i = 0;i < SamplesToDo;i++) \
755 static const Channel chans[] = { \
756 FRONT_LEFT, FRONT_RIGHT, \
757 FRONT_CENTER, LFE, \
758 BACK_LEFT, BACK_RIGHT, \
759 }; \
760 for(j = 0;j < 6;j++) \
762 samp = 0.0f; \
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; \
769 break; \
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, \
777 }; \
778 for(j = 0;j < 7;j++) \
780 samp = 0.0f; \
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; \
787 break; \
788 case AL_FORMAT_71CHN##bits: \
789 for(i = 0;i < SamplesToDo;i++) \
791 static const Channel chans[] = { \
792 FRONT_LEFT, FRONT_RIGHT, \
793 FRONT_CENTER, LFE, \
794 BACK_LEFT, BACK_RIGHT, \
795 SIDE_LEFT, SIDE_RIGHT \
796 }; \
797 for(j = 0;j < 8;j++) \
799 samp = 0.0f; \
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; \
806 break;
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
817 default:
818 break;
821 size -= SamplesToDo;
824 #if defined(HAVE_FESETROUND)
825 fesetround(fpuState);
826 #elif defined(HAVE__CONTROLFP)
827 _controlfp(fpuState, 0xfffff);
828 #endif