Pass dry-path click buffers as parameters to MixSource
[openal-soft.git] / Alc / mixer.c
blob32dc79171bcdf68afbbc268005e05a2f9acda4d9
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 = 0;
49 if(Value < -1.0f) i = -32768;
50 else if(Value < 0.0f) i = (ALint)(Value*32768.0f);
51 else if(Value > 1.0f) i = 32767;
52 else if(Value > 0.0f) i = (ALint)(Value*32767.0f);
54 return ((ALshort)i);
57 static __inline ALubyte aluF2UB(ALfloat Value)
59 ALshort i = aluF2S(Value);
60 return (i>>8)+128;
64 static __inline ALfloat point(ALfloat val1, ALfloat val2, ALint frac)
66 return val1;
67 (void)val2;
68 (void)frac;
70 static __inline ALfloat lerp(ALfloat val1, ALfloat val2, ALint frac)
72 return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
74 static __inline ALfloat cos_lerp(ALfloat val1, ALfloat val2, ALint frac)
76 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
77 return val1 + ((val2-val1)*mult);
81 static void MixSource(ALsource *ALSource, ALCcontext *ALContext,
82 float (*DryBuffer)[OUTPUTCHANNELS], ALuint SamplesToDo,
83 ALfloat *ClickRemoval, ALfloat *PendingClicks)
85 static float DummyBuffer[BUFFERSIZE];
86 static ALfloat DummyClickRemoval[OUTPUTCHANNELS];
87 ALfloat *WetBuffer[MAX_SENDS];
88 ALfloat DrySend[OUTPUTCHANNELS];
89 ALfloat *WetClickRemoval[MAX_SENDS];
90 ALfloat *WetPendingClicks[MAX_SENDS];
91 ALuint i, j, out;
92 ALfloat value, outsamp;
93 ALbufferlistitem *BufferListItem;
94 ALint64 DataSize64,DataPos64;
95 FILTER *DryFilter, *WetFilter[MAX_SENDS];
96 ALfloat WetSend[MAX_SENDS];
97 ALint increment;
98 ALuint DataPosInt, DataPosFrac;
99 resampler_t Resampler;
100 ALuint BuffersPlayed;
101 ALboolean Looping;
102 ALenum State;
104 if(ALSource->NeedsUpdate)
106 ALsource_Update(ALSource, ALContext);
107 ALSource->NeedsUpdate = AL_FALSE;
110 /* Get source info */
111 Resampler = ALSource->Resampler;
112 State = ALSource->state;
113 BuffersPlayed = ALSource->BuffersPlayed;
114 DataPosInt = ALSource->position;
115 DataPosFrac = ALSource->position_fraction;
116 Looping = ALSource->bLooping;
118 for(i = 0;i < OUTPUTCHANNELS;i++)
119 DrySend[i] = ALSource->Params.DryGains[i];
120 for(i = 0;i < MAX_SENDS;i++)
121 WetSend[i] = ALSource->Params.WetGains[i];
123 /* Get fixed point step */
124 increment = ALSource->Params.Step;
126 DryFilter = &ALSource->Params.iirFilter;
127 for(i = 0;i < MAX_SENDS;i++)
129 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
130 if(ALSource->Send[i].Slot)
132 WetBuffer[i] = ALSource->Send[i].Slot->WetBuffer;
133 WetClickRemoval[i] = ALSource->Send[i].Slot->ClickRemoval;
134 WetPendingClicks[i] = ALSource->Send[i].Slot->PendingClicks;
136 else
138 WetBuffer[i] = DummyBuffer;
139 WetClickRemoval[i] = DummyClickRemoval;
140 WetPendingClicks[i] = DummyClickRemoval;
144 /* Get current buffer queue item */
145 BufferListItem = ALSource->queue;
146 for(i = 0;i < BuffersPlayed;i++)
147 BufferListItem = BufferListItem->next;
149 j = 0;
150 do {
151 const ALbuffer *ALBuffer;
152 ALfloat *Data = NULL;
153 ALuint DataSize = 0;
154 ALuint LoopStart = 0;
155 ALuint LoopEnd = 0;
156 ALuint Channels, Bytes;
157 ALuint BufferSize;
159 /* Get buffer info */
160 if((ALBuffer=BufferListItem->buffer) != NULL)
162 Data = ALBuffer->data;
163 DataSize = ALBuffer->size;
164 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
165 LoopStart = ALBuffer->LoopStart;
166 LoopEnd = ALBuffer->LoopEnd;
167 Channels = aluChannelsFromFormat(ALBuffer->format);
168 Bytes = aluBytesFromFormat(ALBuffer->format);
171 if(Looping && ALSource->lSourceType == AL_STATIC)
173 /* If current offset is beyond the loop range, do not loop */
174 if(DataPosInt >= LoopEnd)
175 Looping = AL_FALSE;
177 if(!Looping || ALSource->lSourceType != AL_STATIC)
179 /* Non-looping and non-static sources ignore loop points */
180 LoopStart = 0;
181 LoopEnd = DataSize;
184 if(DataPosInt >= DataSize)
185 goto skipmix;
187 if(BufferListItem->next)
189 ALbuffer *NextBuf = BufferListItem->next->buffer;
190 if(NextBuf && NextBuf->size)
192 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
193 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
194 memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples);
197 else if(Looping)
199 ALbuffer *NextBuf = ALSource->queue->buffer;
200 if(NextBuf && NextBuf->size)
202 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
203 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
204 memcpy(&Data[DataSize*Channels], &NextBuf->data[LoopStart*Channels], ulExtraSamples);
207 else
208 memset(&Data[DataSize*Channels], 0, (BUFFER_PADDING*Channels*Bytes));
210 /* Figure out how many samples we can mix. */
211 DataSize64 = LoopEnd;
212 DataSize64 <<= FRACTIONBITS;
213 DataPos64 = DataPosInt;
214 DataPos64 <<= FRACTIONBITS;
215 DataPos64 += DataPosFrac;
216 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
218 BufferSize = min(BufferSize, (SamplesToDo-j));
220 /* Actual sample mixing loops */
221 if(Channels == 1) /* Mono */
223 #define DO_MIX(resampler) do { \
224 if(j == 0) \
226 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
227 DataPosFrac); \
229 outsamp = lpFilter4PC(DryFilter, 0, value); \
230 ClickRemoval[FRONT_LEFT] -= outsamp*DrySend[FRONT_LEFT]; \
231 ClickRemoval[FRONT_RIGHT] -= outsamp*DrySend[FRONT_RIGHT]; \
232 ClickRemoval[SIDE_LEFT] -= outsamp*DrySend[SIDE_LEFT]; \
233 ClickRemoval[SIDE_RIGHT] -= outsamp*DrySend[SIDE_RIGHT]; \
234 ClickRemoval[BACK_LEFT] -= outsamp*DrySend[BACK_LEFT]; \
235 ClickRemoval[BACK_RIGHT] -= outsamp*DrySend[BACK_RIGHT]; \
236 ClickRemoval[FRONT_CENTER] -= outsamp*DrySend[FRONT_CENTER]; \
237 ClickRemoval[BACK_CENTER] -= outsamp*DrySend[BACK_CENTER]; \
239 for(out = 0;out < MAX_SENDS;out++) \
241 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
242 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
245 while(BufferSize--) \
247 /* First order interpolator */ \
248 value = (resampler)(Data[DataPosInt], Data[DataPosInt+1], \
249 DataPosFrac); \
251 /* Direct path final mix buffer and panning */ \
252 outsamp = lpFilter4P(DryFilter, 0, value); \
253 DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
254 DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
255 DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
256 DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
257 DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
258 DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
259 DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
260 DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
262 /* Room path final mix buffer and panning */ \
263 for(i = 0;i < MAX_SENDS;i++) \
265 outsamp = lpFilter2P(WetFilter[i], 0, value); \
266 WetBuffer[i][j] += outsamp*WetSend[i]; \
269 DataPosFrac += increment; \
270 DataPosInt += DataPosFrac>>FRACTIONBITS; \
271 DataPosFrac &= FRACTIONMASK; \
272 j++; \
274 if(j == SamplesToDo) \
276 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
277 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
278 ((DataPosFrac-increment)&FRACTIONMASK)); \
279 value = (resampler)(Data[pos], Data[pos+1], frac); \
281 outsamp = lpFilter4PC(DryFilter, 0, value); \
282 PendingClicks[FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; \
283 PendingClicks[FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; \
284 PendingClicks[SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; \
285 PendingClicks[SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; \
286 PendingClicks[BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; \
287 PendingClicks[BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; \
288 PendingClicks[FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; \
289 PendingClicks[BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; \
291 for(out = 0;out < MAX_SENDS;out++) \
293 outsamp = lpFilter2PC(WetFilter[out], 0, value); \
294 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
297 } while(0)
299 switch(Resampler)
301 case POINT_RESAMPLER:
302 DO_MIX(point); break;
303 case LINEAR_RESAMPLER:
304 DO_MIX(lerp); break;
305 case COSINE_RESAMPLER:
306 DO_MIX(cos_lerp); break;
307 case RESAMPLER_MIN:
308 case RESAMPLER_MAX:
309 break;
311 #undef DO_MIX
313 else if(Channels == 2) /* Stereo */
315 const int chans[] = {
316 FRONT_LEFT, FRONT_RIGHT,
317 SIDE_LEFT, SIDE_RIGHT,
318 BACK_LEFT, BACK_RIGHT
321 #define DO_MIX(resampler) do { \
322 const ALfloat scaler = 1.0f/Channels; \
323 if(j == 0) \
325 for(i = 0;i < Channels;i++) \
327 value = (resampler)(Data[DataPosInt*Channels + i], \
328 Data[(DataPosInt+1)*Channels + i], \
329 DataPosFrac); \
331 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
332 ClickRemoval[chans[i+0]] -= outsamp*DrySend[chans[i+0]]; \
333 ClickRemoval[chans[i+2]] -= outsamp*DrySend[chans[i+2]]; \
334 ClickRemoval[chans[i+4]] -= outsamp*DrySend[chans[i+4]]; \
336 for(out = 0;out < MAX_SENDS;out++) \
338 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
339 WetClickRemoval[out][0] -= outsamp*WetSend[out] * scaler; \
343 while(BufferSize--) \
345 for(i = 0;i < Channels;i++) \
347 value = (resampler)(Data[DataPosInt*Channels + i], \
348 Data[(DataPosInt+1)*Channels + i], \
349 DataPosFrac); \
351 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
352 DryBuffer[j][chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
353 DryBuffer[j][chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
354 DryBuffer[j][chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
356 for(out = 0;out < MAX_SENDS;out++) \
358 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
359 WetBuffer[out][j] += outsamp*WetSend[out] * scaler; \
363 DataPosFrac += increment; \
364 DataPosInt += DataPosFrac>>FRACTIONBITS; \
365 DataPosFrac &= FRACTIONMASK; \
366 j++; \
368 if(j == SamplesToDo) \
370 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
371 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
372 ((DataPosFrac-increment)&FRACTIONMASK)); \
373 for(i = 0;i < Channels;i++) \
375 value = (resampler)(Data[pos*Channels + i], \
376 Data[(pos+1)*Channels + i], \
377 frac); \
379 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
380 PendingClicks[chans[i+0]] += outsamp*DrySend[chans[i+0]]; \
381 PendingClicks[chans[i+2]] += outsamp*DrySend[chans[i+2]]; \
382 PendingClicks[chans[i+4]] += outsamp*DrySend[chans[i+4]]; \
384 for(out = 0;out < MAX_SENDS;out++) \
386 outsamp = lpFilter1PC(WetFilter[out], chans[i], value); \
387 WetPendingClicks[out][0] += outsamp*WetSend[out] * scaler; \
391 } while(0)
393 switch(Resampler)
395 case POINT_RESAMPLER:
396 DO_MIX(point); break;
397 case LINEAR_RESAMPLER:
398 DO_MIX(lerp); break;
399 case COSINE_RESAMPLER:
400 DO_MIX(cos_lerp); break;
401 case RESAMPLER_MIN:
402 case RESAMPLER_MAX:
403 break;
405 #undef DO_MIX
407 else if(Channels == 4) /* Quad */
409 const int chans[] = {
410 FRONT_LEFT, FRONT_RIGHT,
411 BACK_LEFT, BACK_RIGHT
414 #define DO_MIX(resampler) do { \
415 const ALfloat scaler = 1.0f/Channels; \
416 if(j == 0) \
418 for(i = 0;i < Channels;i++) \
420 value = (resampler)(Data[DataPosInt*Channels + i], \
421 Data[(DataPosInt+1)*Channels + i], \
422 DataPosFrac); \
424 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
425 ClickRemoval[chans[i]] -= outsamp*DrySend[chans[i]]; \
427 for(out = 0;out < MAX_SENDS;out++) \
429 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
430 WetClickRemoval[out][0] -= outsamp*WetSend[out]; \
434 while(BufferSize--) \
436 for(i = 0;i < Channels;i++) \
438 value = (resampler)(Data[DataPosInt*Channels + i], \
439 Data[(DataPosInt+1)*Channels + i], \
440 DataPosFrac); \
442 outsamp = lpFilter2P(DryFilter, chans[i]*2, value); \
443 DryBuffer[j][chans[i]] += outsamp*DrySend[chans[i]]; \
445 for(out = 0;out < MAX_SENDS;out++) \
447 outsamp = lpFilter1P(WetFilter[out], chans[i], value); \
448 WetBuffer[out][j] += outsamp*WetSend[out]*scaler; \
452 DataPosFrac += increment; \
453 DataPosInt += DataPosFrac>>FRACTIONBITS; \
454 DataPosFrac &= FRACTIONMASK; \
455 j++; \
457 if(j == SamplesToDo) \
459 ALuint pos = ((DataPosInt < DataSize) ? DataPosInt : (DataPosInt-1)); \
460 ALuint frac = ((DataPosInt < DataSize) ? DataPosFrac : \
461 ((DataPosFrac-increment)&FRACTIONMASK)); \
462 for(i = 0;i < Channels;i++) \
464 value = (resampler)(Data[pos*Channels + i], \
465 Data[(pos+1)*Channels + i], \
466 frac); \
468 outsamp = lpFilter2PC(DryFilter, chans[i]*2, value); \
469 PendingClicks[chans[i]] += outsamp*DrySend[chans[i]]; \
471 for(out = 0;out < MAX_SENDS;out++) \
473 outsamp = lpFilter1PC(WetFilter[out], chans[out], value) * scaler;\
474 WetPendingClicks[out][0] += outsamp*WetSend[out]; \
478 } while(0)
480 switch(Resampler)
482 case POINT_RESAMPLER:
483 DO_MIX(point); break;
484 case LINEAR_RESAMPLER:
485 DO_MIX(lerp); break;
486 case COSINE_RESAMPLER:
487 DO_MIX(cos_lerp); break;
488 case RESAMPLER_MIN:
489 case RESAMPLER_MAX:
490 break;
493 else if(Channels == 6) /* 5.1 */
495 const int chans[] = {
496 FRONT_LEFT, FRONT_RIGHT,
497 FRONT_CENTER, LFE,
498 BACK_LEFT, BACK_RIGHT
501 switch(Resampler)
503 case POINT_RESAMPLER:
504 DO_MIX(point); break;
505 case LINEAR_RESAMPLER:
506 DO_MIX(lerp); break;
507 case COSINE_RESAMPLER:
508 DO_MIX(cos_lerp); break;
509 case RESAMPLER_MIN:
510 case RESAMPLER_MAX:
511 break;
514 else if(Channels == 7) /* 6.1 */
516 const int chans[] = {
517 FRONT_LEFT, FRONT_RIGHT,
518 FRONT_CENTER, LFE,
519 BACK_CENTER,
520 SIDE_LEFT, SIDE_RIGHT
523 switch(Resampler)
525 case POINT_RESAMPLER:
526 DO_MIX(point); break;
527 case LINEAR_RESAMPLER:
528 DO_MIX(lerp); break;
529 case COSINE_RESAMPLER:
530 DO_MIX(cos_lerp); break;
531 case RESAMPLER_MIN:
532 case RESAMPLER_MAX:
533 break;
536 else if(Channels == 8) /* 7.1 */
538 const int chans[] = {
539 FRONT_LEFT, FRONT_RIGHT,
540 FRONT_CENTER, LFE,
541 BACK_LEFT, BACK_RIGHT,
542 SIDE_LEFT, SIDE_RIGHT
545 switch(Resampler)
547 case POINT_RESAMPLER:
548 DO_MIX(point); break;
549 case LINEAR_RESAMPLER:
550 DO_MIX(lerp); break;
551 case COSINE_RESAMPLER:
552 DO_MIX(cos_lerp); break;
553 case RESAMPLER_MIN:
554 case RESAMPLER_MAX:
555 break;
557 #undef DO_MIX
559 else /* Unknown? */
561 while(BufferSize--)
563 DataPosFrac += increment;
564 DataPosInt += DataPosFrac>>FRACTIONBITS;
565 DataPosFrac &= FRACTIONMASK;
566 j++;
570 skipmix:
571 /* Handle looping sources */
572 if(DataPosInt >= LoopEnd)
574 if(BuffersPlayed < (ALSource->BuffersInQueue-1))
576 BufferListItem = BufferListItem->next;
577 BuffersPlayed++;
578 DataPosInt -= DataSize;
580 else if(Looping)
582 BufferListItem = ALSource->queue;
583 BuffersPlayed = 0;
584 if(ALSource->lSourceType == AL_STATIC)
585 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
586 else
587 DataPosInt -= DataSize;
589 else
591 State = AL_STOPPED;
592 BufferListItem = ALSource->queue;
593 BuffersPlayed = ALSource->BuffersInQueue;
594 DataPosInt = 0;
595 DataPosFrac = 0;
598 } while(State == AL_PLAYING && j < SamplesToDo);
600 /* Update source info */
601 ALSource->state = State;
602 ALSource->BuffersPlayed = BuffersPlayed;
603 ALSource->position = DataPosInt;
604 ALSource->position_fraction = DataPosFrac;
605 ALSource->Buffer = BufferListItem->buffer;
608 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
610 float (*DryBuffer)[OUTPUTCHANNELS];
611 ALfloat (*Matrix)[OUTPUTCHANNELS];
612 ALfloat *ClickRemoval;
613 const ALuint *ChanMap;
614 ALuint SamplesToDo;
615 ALeffectslot *ALEffectSlot;
616 ALCcontext **ctx, **ctx_end;
617 ALsource **src, **src_end;
618 ALfloat samp;
619 int fpuState;
620 ALuint i, j, c;
621 ALsizei e;
623 #if defined(HAVE_FESETROUND)
624 fpuState = fegetround();
625 fesetround(FE_TOWARDZERO);
626 #elif defined(HAVE__CONTROLFP)
627 fpuState = _controlfp(0, 0);
628 _controlfp(_RC_CHOP, _MCW_RC);
629 #else
630 (void)fpuState;
631 #endif
633 DryBuffer = device->DryBuffer;
634 while(size > 0)
636 /* Setup variables */
637 SamplesToDo = min(size, BUFFERSIZE);
639 /* Clear mixing buffer */
640 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
642 SuspendContext(NULL);
643 ctx = device->Contexts;
644 ctx_end = ctx + device->NumContexts;
645 while(ctx != ctx_end)
647 SuspendContext(*ctx);
649 src = (*ctx)->ActiveSources;
650 src_end = src + (*ctx)->ActiveSourceCount;
651 while(src != src_end)
653 if((*src)->state != AL_PLAYING)
655 --((*ctx)->ActiveSourceCount);
656 *src = *(--src_end);
657 continue;
659 MixSource(*src, *ctx, DryBuffer, SamplesToDo,
660 device->ClickRemoval, device->PendingClicks);
661 src++;
664 /* effect slot processing */
665 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
667 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
669 ClickRemoval = ALEffectSlot->ClickRemoval;
670 for(i = 0;i < SamplesToDo;i++)
672 ClickRemoval[0] -= ClickRemoval[0] / 256.0f;
673 ALEffectSlot->WetBuffer[i] += ClickRemoval[0];
675 for(i = 0;i < 1;i++)
677 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
678 ALEffectSlot->PendingClicks[i] = 0.0f;
681 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
683 for(i = 0;i < SamplesToDo;i++)
684 ALEffectSlot->WetBuffer[i] = 0.0f;
687 ProcessContext(*ctx);
688 ctx++;
690 device->SamplesPlayed += SamplesToDo;
691 ProcessContext(NULL);
693 //Post processing loop
694 ClickRemoval = device->ClickRemoval;
695 for(i = 0;i < SamplesToDo;i++)
697 for(c = 0;c < OUTPUTCHANNELS;c++)
699 ClickRemoval[c] -= ClickRemoval[c] / 256.0f;
700 DryBuffer[i][c] += ClickRemoval[c];
703 for(i = 0;i < OUTPUTCHANNELS;i++)
705 device->ClickRemoval[i] += device->PendingClicks[i];
706 device->PendingClicks[i] = 0.0f;
709 ChanMap = device->DevChannels;
710 Matrix = device->ChannelMatrix;
711 switch(device->Format)
713 #define CHECK_WRITE_FORMAT(bits, type, func) \
714 case AL_FORMAT_MONO##bits: \
715 for(i = 0;i < SamplesToDo;i++) \
717 samp = 0.0f; \
718 for(c = 0;c < OUTPUTCHANNELS;c++) \
719 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
720 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
721 buffer = ((type*)buffer) + 1; \
723 break; \
724 case AL_FORMAT_STEREO##bits: \
725 if(device->Bs2b) \
727 for(i = 0;i < SamplesToDo;i++) \
729 float samples[2] = { 0.0f, 0.0f }; \
730 for(c = 0;c < OUTPUTCHANNELS;c++) \
732 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
733 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
735 bs2b_cross_feed(device->Bs2b, samples); \
736 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
737 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
738 buffer = ((type*)buffer) + 2; \
741 else \
743 for(i = 0;i < SamplesToDo;i++) \
745 static const Channel chans[] = { \
746 FRONT_LEFT, FRONT_RIGHT \
747 }; \
748 for(j = 0;j < 2;j++) \
750 samp = 0.0f; \
751 for(c = 0;c < OUTPUTCHANNELS;c++) \
752 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
753 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
755 buffer = ((type*)buffer) + 2; \
758 break; \
759 case AL_FORMAT_QUAD##bits: \
760 for(i = 0;i < SamplesToDo;i++) \
762 static const Channel chans[] = { \
763 FRONT_LEFT, FRONT_RIGHT, \
764 BACK_LEFT, BACK_RIGHT, \
765 }; \
766 for(j = 0;j < 4;j++) \
768 samp = 0.0f; \
769 for(c = 0;c < OUTPUTCHANNELS;c++) \
770 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
771 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
773 buffer = ((type*)buffer) + 4; \
775 break; \
776 case AL_FORMAT_51CHN##bits: \
777 for(i = 0;i < SamplesToDo;i++) \
779 static const Channel chans[] = { \
780 FRONT_LEFT, FRONT_RIGHT, \
781 FRONT_CENTER, LFE, \
782 BACK_LEFT, BACK_RIGHT, \
783 }; \
784 for(j = 0;j < 6;j++) \
786 samp = 0.0f; \
787 for(c = 0;c < OUTPUTCHANNELS;c++) \
788 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
789 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
791 buffer = ((type*)buffer) + 6; \
793 break; \
794 case AL_FORMAT_61CHN##bits: \
795 for(i = 0;i < SamplesToDo;i++) \
797 static const Channel chans[] = { \
798 FRONT_LEFT, FRONT_RIGHT, \
799 FRONT_CENTER, LFE, BACK_CENTER, \
800 SIDE_LEFT, SIDE_RIGHT, \
801 }; \
802 for(j = 0;j < 7;j++) \
804 samp = 0.0f; \
805 for(c = 0;c < OUTPUTCHANNELS;c++) \
806 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
807 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
809 buffer = ((type*)buffer) + 7; \
811 break; \
812 case AL_FORMAT_71CHN##bits: \
813 for(i = 0;i < SamplesToDo;i++) \
815 static const Channel chans[] = { \
816 FRONT_LEFT, FRONT_RIGHT, \
817 FRONT_CENTER, LFE, \
818 BACK_LEFT, BACK_RIGHT, \
819 SIDE_LEFT, SIDE_RIGHT \
820 }; \
821 for(j = 0;j < 8;j++) \
823 samp = 0.0f; \
824 for(c = 0;c < OUTPUTCHANNELS;c++) \
825 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
826 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
828 buffer = ((type*)buffer) + 8; \
830 break;
832 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
833 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
834 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
835 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
836 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
837 #undef AL_FORMAT_STEREO32
838 #undef AL_FORMAT_MONO32
839 #undef CHECK_WRITE_FORMAT
841 default:
842 break;
845 size -= SamplesToDo;
848 #if defined(HAVE_FESETROUND)
849 fesetround(fpuState);
850 #elif defined(HAVE__CONTROLFP)
851 _controlfp(fpuState, 0xfffff);
852 #endif