Better protect against sample overflow when converting float to short
[openal-soft.git] / Alc / mixer.c
blob356a760fcdb9632d0e51077e96e12de5ba32ae28
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)
84 static float DummyBuffer[BUFFERSIZE];
85 static ALfloat DummyClickRemoval[OUTPUTCHANNELS];
86 ALfloat *WetBuffer[MAX_SENDS];
87 ALfloat DrySend[OUTPUTCHANNELS];
88 ALfloat *ClickRemoval, *PendingClicks;
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 ClickRemoval = ALContext->Device->ClickRemoval;
105 PendingClicks = ALContext->Device->PendingClicks;
107 if(ALSource->NeedsUpdate)
109 ALsource_Update(ALSource, ALContext);
110 ALSource->NeedsUpdate = AL_FALSE;
113 /* Get source info */
114 Resampler = ALSource->Resampler;
115 State = ALSource->state;
116 BuffersPlayed = ALSource->BuffersPlayed;
117 DataPosInt = ALSource->position;
118 DataPosFrac = ALSource->position_fraction;
119 Looping = ALSource->bLooping;
121 for(i = 0;i < OUTPUTCHANNELS;i++)
122 DrySend[i] = ALSource->Params.DryGains[i];
123 for(i = 0;i < MAX_SENDS;i++)
124 WetSend[i] = ALSource->Params.WetGains[i];
126 /* Get fixed point step */
127 increment = ALSource->Params.Step;
129 DryFilter = &ALSource->Params.iirFilter;
130 for(i = 0;i < MAX_SENDS;i++)
132 WetFilter[i] = &ALSource->Params.Send[i].iirFilter;
133 WetBuffer[i] = (ALSource->Send[i].Slot ?
134 ALSource->Send[i].Slot->WetBuffer :
135 DummyBuffer);
136 WetClickRemoval[i] = (ALSource->Send[i].Slot ?
137 ALSource->Send[i].Slot->ClickRemoval :
138 DummyClickRemoval);
139 WetPendingClicks[i] = (ALSource->Send[i].Slot ?
140 ALSource->Send[i].Slot->PendingClicks :
141 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 *ALContext;
617 ALfloat samp;
618 int fpuState;
619 ALuint i, j, c;
620 ALsizei e, s;
622 #if defined(HAVE_FESETROUND)
623 fpuState = fegetround();
624 fesetround(FE_TOWARDZERO);
625 #elif defined(HAVE__CONTROLFP)
626 fpuState = _controlfp(0, 0);
627 _controlfp(_RC_CHOP, _MCW_RC);
628 #else
629 (void)fpuState;
630 #endif
632 DryBuffer = device->DryBuffer;
633 while(size > 0)
635 /* Setup variables */
636 SamplesToDo = min(size, BUFFERSIZE);
638 /* Clear mixing buffer */
639 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
641 SuspendContext(NULL);
642 for(c = 0;c < device->NumContexts;c++)
644 ALContext = device->Contexts[c];
645 SuspendContext(ALContext);
647 s = 0;
648 while(s < ALContext->ActiveSourceCount)
650 ALsource *Source = ALContext->ActiveSources[s];
651 if(Source->state != AL_PLAYING)
653 ALsizei end = --(ALContext->ActiveSourceCount);
654 ALContext->ActiveSources[s] = ALContext->ActiveSources[end];
655 continue;
657 MixSource(Source, ALContext, DryBuffer, SamplesToDo);
658 s++;
661 /* effect slot processing */
662 for(e = 0;e < ALContext->EffectSlotMap.size;e++)
664 ALEffectSlot = ALContext->EffectSlotMap.array[e].value;
666 ClickRemoval = ALEffectSlot->ClickRemoval;
667 for(i = 0;i < SamplesToDo;i++)
669 ClickRemoval[0] -= ClickRemoval[0] / 256.0f;
670 ALEffectSlot->WetBuffer[i] += ClickRemoval[0];
672 for(i = 0;i < 1;i++)
674 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
675 ALEffectSlot->PendingClicks[i] = 0.0f;
678 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
680 for(i = 0;i < SamplesToDo;i++)
681 ALEffectSlot->WetBuffer[i] = 0.0f;
683 ProcessContext(ALContext);
685 device->SamplesPlayed += SamplesToDo;
686 ProcessContext(NULL);
688 //Post processing loop
689 ClickRemoval = device->ClickRemoval;
690 for(i = 0;i < SamplesToDo;i++)
692 for(c = 0;c < OUTPUTCHANNELS;c++)
694 ClickRemoval[c] -= ClickRemoval[c] / 256.0f;
695 DryBuffer[i][c] += ClickRemoval[c];
698 for(i = 0;i < OUTPUTCHANNELS;i++)
700 device->ClickRemoval[i] += device->PendingClicks[i];
701 device->PendingClicks[i] = 0.0f;
704 ChanMap = device->DevChannels;
705 Matrix = device->ChannelMatrix;
706 switch(device->Format)
708 #define CHECK_WRITE_FORMAT(bits, type, func) \
709 case AL_FORMAT_MONO##bits: \
710 for(i = 0;i < SamplesToDo;i++) \
712 samp = 0.0f; \
713 for(c = 0;c < OUTPUTCHANNELS;c++) \
714 samp += DryBuffer[i][c] * Matrix[c][FRONT_CENTER]; \
715 ((type*)buffer)[ChanMap[FRONT_CENTER]] = (func)(samp); \
716 buffer = ((type*)buffer) + 1; \
718 break; \
719 case AL_FORMAT_STEREO##bits: \
720 if(device->Bs2b) \
722 for(i = 0;i < SamplesToDo;i++) \
724 float samples[2] = { 0.0f, 0.0f }; \
725 for(c = 0;c < OUTPUTCHANNELS;c++) \
727 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
728 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
730 bs2b_cross_feed(device->Bs2b, samples); \
731 ((type*)buffer)[ChanMap[FRONT_LEFT]] = (func)(samples[0]);\
732 ((type*)buffer)[ChanMap[FRONT_RIGHT]]= (func)(samples[1]);\
733 buffer = ((type*)buffer) + 2; \
736 else \
738 for(i = 0;i < SamplesToDo;i++) \
740 static const Channel chans[] = { \
741 FRONT_LEFT, FRONT_RIGHT \
742 }; \
743 for(j = 0;j < 2;j++) \
745 samp = 0.0f; \
746 for(c = 0;c < OUTPUTCHANNELS;c++) \
747 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
748 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
750 buffer = ((type*)buffer) + 2; \
753 break; \
754 case AL_FORMAT_QUAD##bits: \
755 for(i = 0;i < SamplesToDo;i++) \
757 static const Channel chans[] = { \
758 FRONT_LEFT, FRONT_RIGHT, \
759 BACK_LEFT, BACK_RIGHT, \
760 }; \
761 for(j = 0;j < 4;j++) \
763 samp = 0.0f; \
764 for(c = 0;c < OUTPUTCHANNELS;c++) \
765 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
766 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
768 buffer = ((type*)buffer) + 4; \
770 break; \
771 case AL_FORMAT_51CHN##bits: \
772 for(i = 0;i < SamplesToDo;i++) \
774 static const Channel chans[] = { \
775 FRONT_LEFT, FRONT_RIGHT, \
776 FRONT_CENTER, LFE, \
777 BACK_LEFT, BACK_RIGHT, \
778 }; \
779 for(j = 0;j < 6;j++) \
781 samp = 0.0f; \
782 for(c = 0;c < OUTPUTCHANNELS;c++) \
783 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
784 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
786 buffer = ((type*)buffer) + 6; \
788 break; \
789 case AL_FORMAT_61CHN##bits: \
790 for(i = 0;i < SamplesToDo;i++) \
792 static const Channel chans[] = { \
793 FRONT_LEFT, FRONT_RIGHT, \
794 FRONT_CENTER, LFE, BACK_CENTER, \
795 SIDE_LEFT, SIDE_RIGHT, \
796 }; \
797 for(j = 0;j < 7;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) + 7; \
806 break; \
807 case AL_FORMAT_71CHN##bits: \
808 for(i = 0;i < SamplesToDo;i++) \
810 static const Channel chans[] = { \
811 FRONT_LEFT, FRONT_RIGHT, \
812 FRONT_CENTER, LFE, \
813 BACK_LEFT, BACK_RIGHT, \
814 SIDE_LEFT, SIDE_RIGHT \
815 }; \
816 for(j = 0;j < 8;j++) \
818 samp = 0.0f; \
819 for(c = 0;c < OUTPUTCHANNELS;c++) \
820 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
821 ((type*)buffer)[ChanMap[chans[j]]] = (func)(samp); \
823 buffer = ((type*)buffer) + 8; \
825 break;
827 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
828 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
829 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
830 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
831 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
832 #undef AL_FORMAT_STEREO32
833 #undef AL_FORMAT_MONO32
834 #undef CHECK_WRITE_FORMAT
836 default:
837 break;
840 size -= SamplesToDo;
843 #if defined(HAVE_FESETROUND)
844 fesetround(fpuState);
845 #elif defined(HAVE__CONTROLFP)
846 _controlfp(fpuState, 0xfffff);
847 #endif