Combine two arrays into one
[openal-soft.git] / Alc / mixer.c
blob1ca0fcc067827a5e3a06f56f4eeb7c734a8965fe
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 < 0.0f)
51 i = (ALint)(Value*32768.0f);
52 i = max(-32768, i);
54 else
56 i = (ALint)(Value*32767.0f);
57 i = min( 32767, i);
59 return ((ALshort)i);
62 static __inline ALubyte aluF2UB(ALfloat Value)
64 ALshort i = aluF2S(Value);
65 return (i>>8)+128;
69 static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac)
71 return val1;
72 (void)val2;
73 (void)frac;
75 static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac)
77 return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
79 static __inline ALfloat cos_lerp(ALfloat val1, ALfloat val2, ALint frac)
81 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
82 return val1 + ((val2-val1)*mult);
86 static void MixSource(ALsource *ALSource, ALCcontext *ALContext,
87 float (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo)
89 static float DummyBuffer[BUFFERSIZE];
90 static ALfloat DummyClickRemoval[OUTPUTCHANNELS];
91 ALfloat *WetBuffer[MAX_SENDS];
92 ALfloat DrySend[OUTPUTCHANNELS];
93 ALfloat *ClickRemoval, *PendingClicks;
94 ALfloat *WetClickRemoval[MAX_SENDS];
95 ALfloat *WetPendingClicks[MAX_SENDS];
96 ALuint i, j, out;
97 ALfloat value, outsamp;
98 ALbufferlistitem *BufferListItem;
99 ALint64 DataSize64,DataPos64;
100 FILTER *DryFilter, *WetFilter[MAX_SENDS];
101 ALfloat WetSend[MAX_SENDS];
102 ALint increment;
103 ALuint DataPosInt, DataPosFrac;
104 resampler_t Resampler;
105 ALuint BuffersPlayed;
106 ALboolean Looping;
107 ALenum State;
109 ClickRemoval = ALContext->Device->ClickRemoval;
110 PendingClicks = ALContext->Device->PendingClicks;
112 if(ALSource->NeedsUpdate)
114 ALsource_Update(ALSource, ALContext);
115 ALSource->NeedsUpdate = AL_FALSE;
118 /* Get source info */
119 Resampler = ALSource->Resampler;
120 State = ALSource->state;
121 BuffersPlayed = ALSource->BuffersPlayed;
122 DataPosInt = ALSource->position;
123 DataPosFrac = ALSource->position_fraction;
124 Looping = ALSource->bLooping;
126 for(i = 0;i < OUTPUTCHANNELS;i++)
127 DrySend[i] = ALSource->Params.DryGains[i];
128 for(i = 0;i < MAX_SENDS;i++)
129 WetSend[i] = ALSource->Params.WetGains[i];
131 /* Get fixed point step */
132 increment = ALSource->Params.Step;
134 DryFilter = &ALSource->Params.iirFilter;
135 for(i = 0;i < MAX_SENDS;i++)
137 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
138 WetBuffer[i] = (ALSource->Send[i].Slot ?
139 ALSource->Send[i].Slot->WetBuffer :
140 DummyBuffer);
141 WetClickRemoval[i] = (ALSource->Send[i].Slot ?
142 ALSource->Send[i].Slot->ClickRemoval :
143 DummyClickRemoval);
144 WetPendingClicks[i] = (ALSource->Send[i].Slot ?
145 ALSource->Send[i].Slot->PendingClicks :
146 DummyClickRemoval);
149 /* Get current buffer queue item */
150 BufferListItem = ALSource->queue;
151 for(i = 0;i < BuffersPlayed;i++)
152 BufferListItem = BufferListItem->next;
154 j = 0;
155 do {
156 const ALbuffer *ALBuffer;
157 ALfloat *Data = NULL;
158 ALuint DataSize = 0;
159 ALuint LoopStart = 0;
160 ALuint LoopEnd = 0;
161 ALuint Channels, Bytes;
162 ALuint BufferSize;
164 /* Get buffer info */
165 if((ALBuffer=BufferListItem->buffer) != NULL)
167 Data = ALBuffer->data;
168 DataSize = ALBuffer->size;
169 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
170 LoopStart = ALBuffer->LoopStart;
171 LoopEnd = ALBuffer->LoopEnd;
172 Channels = aluChannelsFromFormat(ALBuffer->format);
173 Bytes = aluBytesFromFormat(ALBuffer->format);
176 if(Looping && ALSource->lSourceType == AL_STATIC)
178 /* If current offset is beyond the loop range, do not loop */
179 if(DataPosInt >= LoopEnd)
180 Looping = AL_FALSE;
182 if(!Looping || ALSource->lSourceType != AL_STATIC)
184 /* Non-looping and non-static sources ignore loop points */
185 LoopStart = 0;
186 LoopEnd = DataSize;
189 if(DataPosInt >= DataSize)
190 goto skipmix;
192 if(BufferListItem->next)
194 ALbuffer *NextBuf = BufferListItem->next->buffer;
195 if(NextBuf && NextBuf->size)
197 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
198 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
199 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
202 else if(Looping)
204 ALbuffer *NextBuf = ALSource->queue->buffer;
205 if(NextBuf && NextBuf->size)
207 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
208 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
209 memcpy(&Data[DataSize*Channels], &NextBuf->data[LoopStart*Channels], ulExtraSamples);
212 else
213 memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
215 /* Figure out how many samples we can mix. */
216 DataSize64 = LoopEnd;
217 DataSize64 <<= FRACTIONBITS;
218 DataPos64 = DataPosInt;
219 DataPos64 <<= FRACTIONBITS;
220 DataPos64 += DataPosFrac;
221 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
223 BufferSize = min(BufferSize, (SamplesToDo-j));
225 /* Actual sample mixing loops */
226 if(Channels == 1) /* Mono */
228 #define DO_MIX(resampler) do { \
229 if(j == 0) \
231 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
232 DataPosFrac); \
234 outsamp = lpFilter4PC(DryFilter, 0, value); \
235 ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \
236 ClickRemoval[FRONT_RIGHT] -= outsamp*DrySend[FRONT_RIGHT]; \
237 ClickRemoval[SIDE_LEFT] -= outsamp*DrySend[SIDE_LEFT]; \
238 ClickRemoval[SIDE_RIGHT] -= outsamp*DrySend[SIDE_RIGHT]; \
239 ClickRemoval[BACK_LEFT] -= outsamp*DrySend[BACK_LEFT]; \
240 ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \
241 ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \
242 ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \
244 for(out = 0;out < MAX_SENDS;out++) \
246 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
247 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
250 while(BufferSize--) \
252 /* First order interpolator */ \
253 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
254 DataPosFrac); \
256 /* Direct path final mix buffer and panning */ \
257 outsamp = lpFilter4P(DryFilter, 0, value); \
258 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
259 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
260 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
261 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
262 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
263 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
264 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
265 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
267 /* Room path final mix buffer and panning */ \
268 for(i = 0;i < MAX_SENDS;i++) \
270 outsamp = lpFilter2P(WetFilter[i], 0, value); \
271 WetBuffer[i][j] += outsamp*WetSend[i]; \
274 DataPosFrac += increment; \
275 DataPosInt += DataPosFrac>>FRACTIONBITS; \
276 DataPosFrac &= FRACTIONMASK; \
277 j++; \
279 if(j == SamplesToDo) \
281 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
282 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
283 ((DataPosFrac-increment)&FRACTIONMASK)); \
284 value = (resampler)(Data[pos], Data[pos+1], frac); \
286 outsamp = lpFilter4PC(DryFilter, 0, value); \
287 PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
288 PendingClicks[FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
289 PendingClicks[SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
290 PendingClicks[SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
291 PendingClicks[BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
292 PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
293 PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
294 PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
296 for(out = 0;out < MAX_SENDS;out++) \
298 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
299 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
302 } while(0)
304 switch(Resampler)
306 case POINT_RESAMPLER:
307 DO_MIX(point); break;
308 case LINEAR_RESAMPLER:
309 DO_MIX(lerp); break;
310 case COSINE_RESAMPLER:
311 DO_MIX(cos_lerp); break;
312 case RESAMPLER_MIN:
313 case RESAMPLER_MAX:
314 break;
316 #undef DO_MIX
318 else if(Channels == 2) /* Stereo */
320 const int chans[] = {
321 FRONT_LEFT, FRONT_RIGHT,
322 SIDE_LEFT, SIDE_RIGHT,
323 BACK_LEFT, BACK_RIGHT
326 #define DO_MIX(resampler) do { \
327 const ALfloat scaler = 1.0f/Channels; \
328 if(j == 0) \
330 for(i = 0;i < Channels;i++) \
332 value = (resampler)(Data[DataPosInt*Channels + i], \
333 Data[(DataPosInt+1)*Channels + i], \
334 DataPosFrac); \
336 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
337 ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \
338 ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \
339 ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \
341 for(out = 0;out < MAX_SENDS;out++) \
343 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
344 WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \
348 while(BufferSize--) \
350 for(i = 0;i < Channels;i++) \
352 value = (resampler)(Data[DataPosInt*Channels + i], \
353 Data[(DataPosInt+1)*Channels + i], \
354 DataPosFrac); \
356 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
357 DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
358 DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
359 DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
361 for(out = 0;out < MAX_SENDS;out++) \
363 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
364 WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \
368 DataPosFrac += increment; \
369 DataPosInt += DataPosFrac>>FRACTIONBITS; \
370 DataPosFrac &= FRACTIONMASK; \
371 j++; \
373 if(j == SamplesToDo) \
375 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
376 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
377 ((DataPosFrac-increment)&FRACTIONMASK)); \
378 for(i = 0;i < Channels;i++) \
380 value = (resampler)(Data[pos*Channels + i], \
381 Data[(pos+1)*Channels + i], \
382 frac); \
384 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
385 PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
386 PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
387 PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
389 for(out = 0;out < MAX_SENDS;out++) \
391 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
392 WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \
396 } while(0)
398 switch(Resampler)
400 case POINT_RESAMPLER:
401 DO_MIX(point); break;
402 case LINEAR_RESAMPLER:
403 DO_MIX(lerp); break;
404 case COSINE_RESAMPLER:
405 DO_MIX(cos_lerp); break;
406 case RESAMPLER_MIN:
407 case RESAMPLER_MAX:
408 break;
410 #undef DO_MIX
412 else if(Channels == 4) /* Quad */
414 const int chans[] = {
415 FRONT_LEFT, FRONT_RIGHT,
416 BACK_LEFT, BACK_RIGHT
419 #define DO_MIX(resampler) do { \
420 const ALfloat scaler = 1.0f/Channels; \
421 if(j == 0) \
423 for(i = 0;i < Channels;i++) \
425 value = (resampler)(Data[DataPosInt*Channels + i], \
426 Data[(DataPosInt+1)*Channels + i], \
427 DataPosFrac); \
429 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
430 ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \
432 for(out = 0;out < MAX_SENDS;out++) \
434 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
435 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
439 while(BufferSize--) \
441 for(i = 0;i < Channels;i++) \
443 value = (resampler)(Data[DataPosInt*Channels + i], \
444 Data[(DataPosInt+1)*Channels + i], \
445 DataPosFrac); \
447 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
448 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
450 for(out = 0;out < MAX_SENDS;out++) \
452 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
453 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
457 DataPosFrac += increment; \
458 DataPosInt += DataPosFrac>>FRACTIONBITS; \
459 DataPosFrac &= FRACTIONMASK; \
460 j++; \
462 if(j == SamplesToDo) \
464 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
465 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
466 ((DataPosFrac-increment)&FRACTIONMASK)); \
467 for(i = 0;i < Channels;i++) \
469 value = (resampler)(Data[pos*Channels + i], \
470 Data[(pos+1)*Channels + i], \
471 frac); \
473 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
474 PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \
476 for(out = 0;out < MAX_SENDS;out++) \
478 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
479 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
483 } while(0)
485 switch(Resampler)
487 case POINT_RESAMPLER:
488 DO_MIX(point); break;
489 case LINEAR_RESAMPLER:
490 DO_MIX(lerp); break;
491 case COSINE_RESAMPLER:
492 DO_MIX(cos_lerp); break;
493 case RESAMPLER_MIN:
494 case RESAMPLER_MAX:
495 break;
498 else if(Channels == 6) /* 5.1 */
500 const int chans[] = {
501 FRONT_LEFT, FRONT_RIGHT,
502 FRONT_CENTER, LFE,
503 BACK_LEFT, BACK_RIGHT
506 switch(Resampler)
508 case POINT_RESAMPLER:
509 DO_MIX(point); break;
510 case LINEAR_RESAMPLER:
511 DO_MIX(lerp); break;
512 case COSINE_RESAMPLER:
513 DO_MIX(cos_lerp); break;
514 case RESAMPLER_MIN:
515 case RESAMPLER_MAX:
516 break;
519 else if(Channels == 7) /* 6.1 */
521 const int chans[] = {
522 FRONT_LEFT, FRONT_RIGHT,
523 FRONT_CENTER, LFE,
524 BACK_CENTER,
525 SIDE_LEFT, SIDE_RIGHT
528 switch(Resampler)
530 case POINT_RESAMPLER:
531 DO_MIX(point); break;
532 case LINEAR_RESAMPLER:
533 DO_MIX(lerp); break;
534 case COSINE_RESAMPLER:
535 DO_MIX(cos_lerp); break;
536 case RESAMPLER_MIN:
537 case RESAMPLER_MAX:
538 break;
541 else if(Channels == 8) /* 7.1 */
543 const int chans[] = {
544 FRONT_LEFT, FRONT_RIGHT,
545 FRONT_CENTER, LFE,
546 BACK_LEFT, BACK_RIGHT,
547 SIDE_LEFT, SIDE_RIGHT
550 switch(Resampler)
552 case POINT_RESAMPLER:
553 DO_MIX(point); break;
554 case LINEAR_RESAMPLER:
555 DO_MIX(lerp); break;
556 case COSINE_RESAMPLER:
557 DO_MIX(cos_lerp); break;
558 case RESAMPLER_MIN:
559 case RESAMPLER_MAX:
560 break;
562 #undef DO_MIX
564 else /* Unknown? */
566 while(BufferSize--)
568 DataPosFrac += increment;
569 DataPosInt += DataPosFrac>>FRACTIONBITS;
570 DataPosFrac &= FRACTIONMASK;
571 j++;
575 skipmix:
576 /* Handle looping sources */
577 if(DataPosInt >= LoopEnd)
579 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
581 BufferListItem = BufferListItem->next;
582 BuffersPlayed++;
583 DataPosInt -= DataSize;
585 else if(Looping)
587 BufferListItem = ALSource->queue;
588 BuffersPlayed = 0;
589 if(ALSource->lSourceType == AL_STATIC)
590 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
591 else
592 DataPosInt -= DataSize;
594 else
596 State = AL_STOPPED;
597 BufferListItem = ALSource->queue;
598 BuffersPlayed = ALSource->BuffersInQueue;
599 DataPosInt = 0;
600 DataPosFrac = 0;
603 } while(State == AL_PLAYING && j < SamplesToDo);
605 /* Update source info */
606 ALSource->state = State;
607 ALSource->BuffersPlayed = BuffersPlayed;
608 ALSource->position = DataPosInt;
609 ALSource->position_fraction = DataPosFrac;
610 ALSource->Buffer = BufferListItem->buffer;
612 ALSource->FirstStart = AL_FALSE;
615 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
617 float (*DryBuffer)[OUTPUTCHANNELS];
618 ALfloat (*Matrix)[OUTPUTCHANNELS];
619 ALfloat *ClickRemoval;
620 const ALuint *ChanMap;
621 ALuint SamplesToDo;
622 ALeffectslot *ALEffectSlot;
623 ALCcontext *ALContext;
624 ALfloat samp;
625 int fpuState;
626 ALuint i, j, c;
627 ALsizei e, s;
629 #if defined(HAVE_FESETROUND)
630 fpuState = fegetround();
631 fesetround(FE_TOWARDZERO);
632 #elif defined(HAVE__CONTROLFP)
633 fpuState = _controlfp(0, 0);
634 _controlfp(_RC_CHOP, _MCW_RC);
635 #else
636 (void)fpuState;
637 #endif
639 DryBuffer = device->DryBuffer;
640 while(size > 0)
642 /* Setup variables */
643 SamplesToDo = min(size, BUFFERSIZE);
645 /* Clear mixing buffer */
646 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
648 SuspendContext(NULL);
649 for(c = 0;c < device->NumContexts;c++)
651 ALContext = device->Contexts[c];
652 SuspendContext(ALContext);
654 s = 0;
655 while(s < ALContext->ActiveSourceCount)
657 ALsource *Source = ALContext->ActiveSources[s];
658 if(Source->state != AL_PLAYING)
660 ALsizei end = --(ALContext->ActiveSourceCount);
661 ALContext->ActiveSources[s] = ALContext->ActiveSources[end];
662 continue;
664 MixSource(Source, ALContext, DryBuffer, SamplesToDo);
665 s++;
668 /* effect slot processing */
669 for(e = 0;e < ALContext->EffectSlotMap.size;e++)
671 ALEffectSlot = ALContext->EffectSlotMap.array[e].value;
673 ClickRemoval = ALEffectSlot->ClickRemoval;
674 for(i = 0;i < SamplesToDo;i++)
676 ClickRemoval[0] -= ClickRemoval[0] / 256.0f;
677 ALEffectSlot->WetBuffer[i] += ClickRemoval[0];
679 for(i = 0;i < 1;i++)
681 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
682 ALEffectSlot->PendingClicks[i] = 0.0f;
685 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
687 for(i = 0;i < SamplesToDo;i++)
688 ALEffectSlot->WetBuffer[i] = 0.0f;
690 ProcessContext(ALContext);
692 device->SamplesPlayed += SamplesToDo;
693 ProcessContext(NULL);
695 //Post processing loop
696 ClickRemoval = device->ClickRemoval;
697 for(i = 0;i < SamplesToDo;i++)
699 for(c = 0;c < OUTPUTCHANNELS;c++)
701 ClickRemoval[c] -= ClickRemoval[c] / 256.0f;
702 DryBuffer[i][c] += ClickRemoval[c];
705 for(i = 0;i < OUTPUTCHANNELS;i++)
707 device->ClickRemoval[i] += device->PendingClicks[i];
708 device->PendingClicks[i] = 0.0f;
711 ChanMap = device->DevChannels;
712 Matrix = device->ChannelMatrix;
713 switch(device->Format)
715 #define CHECK_WRITE_FORMAT(bits, type, func) \
716 case AL_FORMAT_MONO##bits: \
717 for(i = 0;i < SamplesToDo;i++) \
719 samp = 0.0f; \
720 for(c = 0;c < OUTPUTCHANNELS;c++) \
721 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
722 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
723 buffer = ((type*)buffer) + 1; \
725 break; \
726 case AL_FORMAT_STEREO##bits: \
727 if(device->Bs2b) \
729 for(i = 0;i < SamplesToDo;i++) \
731 float samples[2] = { 0.0f, 0.0f }; \
732 for(c = 0;c < OUTPUTCHANNELS;c++) \
734 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
735 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
737 bs2b_cross_feed(device->Bs2b, samples); \
738 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
739 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
740 buffer = ((type*)buffer) + 2; \
743 else \
745 for(i = 0;i < SamplesToDo;i++) \
747 static const Channel chans[] = { \
748 FRONT_LEFT, FRONT_RIGHT \
749 }; \
750 for(j = 0;j < 2;j++) \
752 samp = 0.0f; \
753 for(c = 0;c < OUTPUTCHANNELS;c++) \
754 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
755 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
757 buffer = ((type*)buffer) + 2; \
760 break; \
761 case AL_FORMAT_QUAD##bits: \
762 for(i = 0;i < SamplesToDo;i++) \
764 static const Channel chans[] = { \
765 FRONT_LEFT, FRONT_RIGHT, \
766 BACK_LEFT, BACK_RIGHT, \
767 }; \
768 for(j = 0;j < 4;j++) \
770 samp = 0.0f; \
771 for(c = 0;c < OUTPUTCHANNELS;c++) \
772 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
773 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
775 buffer = ((type*)buffer) + 4; \
777 break; \
778 case AL_FORMAT_51CHN##bits: \
779 for(i = 0;i < SamplesToDo;i++) \
781 static const Channel chans[] = { \
782 FRONT_LEFT, FRONT_RIGHT, \
783 FRONT_CENTER, LFE, \
784 BACK_LEFT, BACK_RIGHT, \
785 }; \
786 for(j = 0;j < 6;j++) \
788 samp = 0.0f; \
789 for(c = 0;c < OUTPUTCHANNELS;c++) \
790 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
791 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
793 buffer = ((type*)buffer) + 6; \
795 break; \
796 case AL_FORMAT_61CHN##bits: \
797 for(i = 0;i < SamplesToDo;i++) \
799 static const Channel chans[] = { \
800 FRONT_LEFT, FRONT_RIGHT, \
801 FRONT_CENTER, LFE, BACK_CENTER, \
802 SIDE_LEFT, SIDE_RIGHT, \
803 }; \
804 for(j = 0;j < 7;j++) \
806 samp = 0.0f; \
807 for(c = 0;c < OUTPUTCHANNELS;c++) \
808 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
809 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
811 buffer = ((type*)buffer) + 7; \
813 break; \
814 case AL_FORMAT_71CHN##bits: \
815 for(i = 0;i < SamplesToDo;i++) \
817 static const Channel chans[] = { \
818 FRONT_LEFT, FRONT_RIGHT, \
819 FRONT_CENTER, LFE, \
820 BACK_LEFT, BACK_RIGHT, \
821 SIDE_LEFT, SIDE_RIGHT \
822 }; \
823 for(j = 0;j < 8;j++) \
825 samp = 0.0f; \
826 for(c = 0;c < OUTPUTCHANNELS;c++) \
827 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
828 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
830 buffer = ((type*)buffer) + 8; \
832 break;
834 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
835 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
836 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
837 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
838 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
839 #undef AL_FORMAT_STEREO32
840 #undef AL_FORMAT_MONO32
841 #undef CHECK_WRITE_FORMAT
843 default:
844 break;
847 size -= SamplesToDo;
850 #if defined(HAVE_FESETROUND)
851 fesetround(fpuState);
852 #elif defined(HAVE__CONTROLFP)
853 _controlfp(fpuState, 0xfffff);
854 #endif