Clarify a check
[openal-soft.git] / Alc / mixer.c
blob640bfe889cc487239450d92c8bd62508b5779f23
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.0f);
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 / 32767.0f;
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 / 32767.0f;
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 / 32767.0f;
98 #define DO_MIX_MONO(S,sampler) do { \
99 ALuint pos = DataPosInt; \
100 ALuint frac = DataPosFrac; \
101 ALfloat DrySend[OUTPUTCHANNELS]; \
102 FILTER *DryFilter; \
103 ALuint BufferIdx; \
104 ALuint i, out; \
105 ALfloat value; \
107 DryFilter = &Source->Params.iirFilter; \
108 for(i = 0;i < OUTPUTCHANNELS;i++) \
109 DrySend[i] = Source->Params.DryGains[i]; \
111 if(j == 0) \
113 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
115 value = lpFilter4PC(DryFilter, 0, value); \
116 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
117 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
118 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
119 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
120 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
121 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
122 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
123 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
125 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
127 /* First order interpolator */ \
128 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
130 /* Direct path final mix buffer and panning */ \
131 value = lpFilter4P(DryFilter, 0, value); \
132 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
133 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
134 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
135 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
136 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
137 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
138 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
139 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
141 frac += increment; \
142 pos += frac>>FRACTIONBITS; \
143 frac &= FRACTIONMASK; \
144 j++; \
146 if(j == SamplesToDo) \
148 ALuint p = pos; \
149 ALuint f = frac; \
150 if(p >= LoopEnd) \
152 ALuint64 pos64 = pos; \
153 pos64 <<= FRACTIONBITS; \
154 pos64 += frac; \
155 pos64 -= increment; \
156 p = pos64>>FRACTIONBITS; \
157 f = pos64&FRACTIONMASK; \
159 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
161 value = lpFilter4PC(DryFilter, 0, value); \
162 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
163 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
164 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
165 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
166 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
167 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
168 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
169 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
172 for(out = 0;out < MAX_SENDS;out++) \
174 ALfloat WetSend; \
175 ALfloat *WetBuffer; \
176 ALfloat *WetClickRemoval; \
177 ALfloat *WetPendingClicks; \
178 FILTER *WetFilter; \
180 if(!Source->Send[out].Slot || \
181 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
182 continue; \
184 WetSend = Source->Params.WetGains[out]; \
185 WetBuffer = Source->Send[out].Slot->WetBuffer; \
186 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
187 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
188 WetFilter = &Source->Params.Send[out].iirFilter; \
190 pos = DataPosInt; \
191 frac = DataPosFrac; \
192 j -= BufferSize; \
194 if(j == 0) \
196 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
198 value = lpFilter2PC(WetFilter, 0, value); \
199 WetClickRemoval[0] -= value*WetSend; \
201 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
203 /* First order interpolator */ \
204 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
206 /* Room path final mix buffer and panning */ \
207 value = lpFilter2P(WetFilter, 0, value); \
208 WetBuffer[j] += value*WetSend; \
210 frac += increment; \
211 pos += frac>>FRACTIONBITS; \
212 frac &= FRACTIONMASK; \
213 j++; \
215 if(j == SamplesToDo) \
217 ALuint p = pos; \
218 ALuint f = frac; \
219 if(p >= LoopEnd) \
221 ALuint64 pos64 = pos; \
222 pos64 <<= FRACTIONBITS; \
223 pos64 += frac; \
224 pos64 -= increment; \
225 p = pos64>>FRACTIONBITS; \
226 f = pos64&FRACTIONMASK; \
228 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
230 value = lpFilter2PC(WetFilter, 0, value); \
231 WetPendingClicks[0] += value*WetSend; \
234 DataPosInt = pos; \
235 DataPosFrac = frac; \
236 } while(0)
238 #define DO_MIX_STEREO(S,sampler) do { \
239 const ALfloat scaler = 1.0f/Channels; \
240 ALuint pos = DataPosInt; \
241 ALuint frac = DataPosFrac; \
242 ALfloat DrySend[OUTPUTCHANNELS]; \
243 FILTER *DryFilter; \
244 ALuint BufferIdx; \
245 ALuint i, out; \
246 ALfloat value; \
248 DryFilter = &Source->Params.iirFilter; \
249 for(i = 0;i < OUTPUTCHANNELS;i++) \
250 DrySend[i] = Source->Params.DryGains[i]; \
252 if(j == 0) \
254 for(i = 0;i < Channels;i++) \
256 value = sampler##S(Data.p##S[pos*Channels + i], \
257 Data.p##S[(pos+1)*Channels + i], frac); \
259 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
260 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
261 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
262 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
265 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
267 for(i = 0;i < Channels;i++) \
269 value = sampler##S(Data.p##S[pos*Channels + i], \
270 Data.p##S[(pos+1)*Channels + i], frac); \
272 value = lpFilter2P(DryFilter, chans[i]*2, value); \
273 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
274 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
275 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
278 frac += increment; \
279 pos += frac>>FRACTIONBITS; \
280 frac &= FRACTIONMASK; \
281 j++; \
283 if(j == SamplesToDo) \
285 ALuint p = pos; \
286 ALuint f = frac; \
287 if(p >= LoopEnd) \
289 ALuint64 pos64 = pos; \
290 pos64 <<= FRACTIONBITS; \
291 pos64 += frac; \
292 pos64 -= increment; \
293 p = pos64>>FRACTIONBITS; \
294 f = pos64&FRACTIONMASK; \
296 for(i = 0;i < Channels;i++) \
298 value = sampler##S(Data.p##S[p*Channels + i], \
299 Data.p##S[(p+1)*Channels + i], f); \
301 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
302 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
303 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
304 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
308 for(out = 0;out < MAX_SENDS;out++) \
310 ALfloat WetSend; \
311 ALfloat *WetBuffer; \
312 ALfloat *WetClickRemoval; \
313 ALfloat *WetPendingClicks; \
314 FILTER *WetFilter; \
316 if(!Source->Send[out].Slot || \
317 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
318 continue; \
320 WetSend = Source->Params.WetGains[out]; \
321 WetBuffer = Source->Send[out].Slot->WetBuffer; \
322 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
323 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
324 WetFilter = &Source->Params.Send[out].iirFilter; \
326 pos = DataPosInt; \
327 frac = DataPosFrac; \
328 j -= BufferSize; \
330 if(j == 0) \
332 for(i = 0;i < Channels;i++) \
334 value = sampler##S(Data.p##S[pos*Channels + i], \
335 Data.p##S[(pos+1)*Channels + i], frac); \
337 value = lpFilter1PC(WetFilter, chans[i], value); \
338 WetClickRemoval[0] -= value*WetSend * scaler; \
341 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
343 for(i = 0;i < Channels;i++) \
345 value = sampler##S(Data.p##S[pos*Channels + i], \
346 Data.p##S[(pos+1)*Channels + i], frac); \
348 value = lpFilter1P(WetFilter, chans[i], value); \
349 WetBuffer[j] += value*WetSend * scaler; \
352 frac += increment; \
353 pos += frac>>FRACTIONBITS; \
354 frac &= FRACTIONMASK; \
355 j++; \
357 if(j == SamplesToDo) \
359 ALuint p = pos; \
360 ALuint f = frac; \
361 if(p >= LoopEnd) \
363 ALuint64 pos64 = pos; \
364 pos64 <<= FRACTIONBITS; \
365 pos64 += frac; \
366 pos64 -= increment; \
367 p = pos64>>FRACTIONBITS; \
368 f = pos64&FRACTIONMASK; \
370 for(i = 0;i < Channels;i++) \
372 value = sampler##S(Data.p##S[p*Channels + i], \
373 Data.p##S[(p+1)*Channels + i], f); \
375 value = lpFilter1PC(WetFilter, chans[i], value); \
376 WetPendingClicks[0] += value*WetSend * scaler; \
380 DataPosInt = pos; \
381 DataPosFrac = frac; \
382 } while(0)
384 #define DO_MIX_MC(S,sampler) do { \
385 const ALfloat scaler = 1.0f/Channels; \
386 ALuint pos = DataPosInt; \
387 ALuint frac = DataPosFrac; \
388 ALfloat DrySend[OUTPUTCHANNELS]; \
389 FILTER *DryFilter; \
390 ALuint BufferIdx; \
391 ALuint i, out; \
392 ALfloat value; \
394 DryFilter = &Source->Params.iirFilter; \
395 for(i = 0;i < OUTPUTCHANNELS;i++) \
396 DrySend[i] = Source->Params.DryGains[i]; \
398 if(j == 0) \
400 for(i = 0;i < Channels;i++) \
402 value = sampler##S(Data.p##S[pos*Channels + i], \
403 Data.p##S[(pos+1)*Channels + i], frac); \
405 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
406 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
409 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
411 for(i = 0;i < Channels;i++) \
413 value = sampler##S(Data.p##S[pos*Channels + i], \
414 Data.p##S[(pos+1)*Channels + i], frac); \
416 value = lpFilter2P(DryFilter, chans[i]*2, value); \
417 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
420 frac += increment; \
421 pos += frac>>FRACTIONBITS; \
422 frac &= FRACTIONMASK; \
423 j++; \
425 if(j == SamplesToDo) \
427 ALuint p = pos; \
428 ALuint f = frac; \
429 if(p >= LoopEnd) \
431 ALuint64 pos64 = pos; \
432 pos64 <<= FRACTIONBITS; \
433 pos64 += frac; \
434 pos64 -= increment; \
435 p = pos64>>FRACTIONBITS; \
436 f = pos64&FRACTIONMASK; \
438 for(i = 0;i < Channels;i++) \
440 value = sampler##S(Data.p##S[p*Channels + i], \
441 Data.p##S[(p+1)*Channels + i], f); \
443 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
444 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
448 for(out = 0;out < MAX_SENDS;out++) \
450 ALfloat WetSend; \
451 ALfloat *WetBuffer; \
452 ALfloat *WetClickRemoval; \
453 ALfloat *WetPendingClicks; \
454 FILTER *WetFilter; \
456 if(!Source->Send[out].Slot || \
457 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
458 continue; \
460 WetSend = Source->Params.WetGains[out]; \
461 WetBuffer = Source->Send[out].Slot->WetBuffer; \
462 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
463 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
464 WetFilter = &Source->Params.Send[out].iirFilter; \
466 pos = DataPosInt; \
467 frac = DataPosFrac; \
468 j -= BufferSize; \
470 if(j == 0) \
472 for(i = 0;i < Channels;i++) \
474 value = sampler##S(Data.p##S[pos*Channels + i], \
475 Data.p##S[(pos+1)*Channels + i], frac); \
477 value = lpFilter1PC(WetFilter, chans[i], value); \
478 WetClickRemoval[0] -= value*WetSend * scaler; \
481 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
483 for(i = 0;i < Channels;i++) \
485 value = sampler##S(Data.p##S[pos*Channels + i], \
486 Data.p##S[(pos+1)*Channels + i], frac); \
488 value = lpFilter1P(WetFilter, chans[i], value); \
489 WetBuffer[j] += value*WetSend * scaler; \
492 frac += increment; \
493 pos += frac>>FRACTIONBITS; \
494 frac &= FRACTIONMASK; \
495 j++; \
497 if(j == SamplesToDo) \
499 ALuint p = pos; \
500 ALuint f = frac; \
501 if(p >= LoopEnd) \
503 ALuint64 pos64 = pos; \
504 pos64 <<= FRACTIONBITS; \
505 pos64 += frac; \
506 pos64 -= increment; \
507 p = pos64>>FRACTIONBITS; \
508 f = pos64&FRACTIONMASK; \
510 for(i = 0;i < Channels;i++) \
512 value = sampler##S(Data.p##S[p*Channels + i], \
513 Data.p##S[(p+1)*Channels + i], f); \
515 value = lpFilter1PC(WetFilter, chans[i], value); \
516 WetPendingClicks[0] += value*WetSend * scaler; \
520 DataPosInt = pos; \
521 DataPosFrac = frac; \
522 } while(0)
525 #define MIX_MONO(S) do { \
526 switch(Source->Resampler) \
528 case POINT_RESAMPLER: \
529 DO_MIX_MONO(S,point); break; \
530 case LINEAR_RESAMPLER: \
531 DO_MIX_MONO(S,lerp); break; \
532 case COSINE_RESAMPLER: \
533 DO_MIX_MONO(S,cos_lerp); break; \
534 case RESAMPLER_MIN: \
535 case RESAMPLER_MAX: \
536 break; \
538 } while(0)
540 #define MIX_STEREO(S) do { \
541 const int chans[] = { \
542 FRONT_LEFT, FRONT_RIGHT, \
543 SIDE_LEFT, SIDE_RIGHT, \
544 BACK_LEFT, BACK_RIGHT \
545 }; \
547 switch(Source->Resampler) \
549 case POINT_RESAMPLER: \
550 DO_MIX_STEREO(S,point); break; \
551 case LINEAR_RESAMPLER: \
552 DO_MIX_STEREO(S,lerp); break; \
553 case COSINE_RESAMPLER: \
554 DO_MIX_STEREO(S,cos_lerp); break; \
555 case RESAMPLER_MIN: \
556 case RESAMPLER_MAX: \
557 break; \
559 } while(0)
561 #define MIX_MC(S,...) do { \
562 const int chans[] = { __VA_ARGS__ }; \
564 switch(Source->Resampler) \
566 case POINT_RESAMPLER: \
567 DO_MIX_MC(S,point); break; \
568 case LINEAR_RESAMPLER: \
569 DO_MIX_MC(S,lerp); break; \
570 case COSINE_RESAMPLER: \
571 DO_MIX_MC(S,cos_lerp); break; \
572 case RESAMPLER_MIN: \
573 case RESAMPLER_MAX: \
574 break; \
576 } while(0)
579 #define MIX(S) do { \
580 if(Channels == 1) /* Mono */ \
581 MIX_MONO(S); \
582 else if(Channels == 2) /* Stereo */ \
583 MIX_STEREO(S); \
584 else if(Channels == 4) /* Quad */ \
585 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
586 BACK_LEFT, BACK_RIGHT); \
587 else if(Channels == 6) /* 5.1 */ \
588 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
589 FRONT_CENTER, LFE, \
590 BACK_LEFT, BACK_RIGHT); \
591 else if(Channels == 7) /* 6.1 */ \
592 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
593 FRONT_CENTER, LFE, \
594 BACK_CENTER, \
595 SIDE_LEFT, SIDE_RIGHT); \
596 else if(Channels == 8) /* 7.1 */ \
597 MIX_MC(S, FRONT_LEFT, FRONT_RIGHT, \
598 FRONT_CENTER, LFE, \
599 BACK_LEFT, BACK_RIGHT, \
600 SIDE_LEFT, SIDE_RIGHT); \
601 } while(0)
604 ALvoid MixSource(ALsource *Source, ALuint SamplesToDo,
605 ALfloat (*DryBuffer)[OUTPUTCHANNELS],
606 ALfloat *ClickRemoval, ALfloat *PendingClicks)
608 ALbufferlistitem *BufferListItem;
609 ALint64 DataSize64,DataPos64;
610 ALint increment;
611 ALuint DataPosInt, DataPosFrac;
612 ALuint BuffersPlayed;
613 ALboolean Looping;
614 ALenum State;
615 ALuint i, j;
617 /* Get source info */
618 State = Source->state;
619 BuffersPlayed = Source->BuffersPlayed;
620 DataPosInt = Source->position;
621 DataPosFrac = Source->position_fraction;
622 Looping = Source->bLooping;
624 /* Get fixed point step */
625 increment = Source->Params.Step;
627 /* Get current buffer queue item */
628 BufferListItem = Source->queue;
629 for(i = 0;i < BuffersPlayed;i++)
630 BufferListItem = BufferListItem->next;
632 j = 0;
633 do {
634 const ALbuffer *ALBuffer;
635 union {
636 ALfloat *p32;
637 ALshort *p16;
638 ALubyte *p8;
639 } Data = { NULL };
640 ALuint DataSize = 0;
641 ALuint LoopStart = 0;
642 ALuint LoopEnd = 0;
643 ALuint Channels, Bytes;
644 ALuint BufferSize;
646 /* Get buffer info */
647 if((ALBuffer=BufferListItem->buffer) != NULL)
649 Data.p8 = ALBuffer->data;
650 DataSize = ALBuffer->size;
651 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
652 Channels = aluChannelsFromFormat(ALBuffer->format);
653 Bytes = aluBytesFromFormat(ALBuffer->format);
655 LoopStart = 0;
656 LoopEnd = DataSize;
657 if(Looping && Source->lSourceType == AL_STATIC)
659 /* If current pos is beyond the loop range, do not loop */
660 if(DataPosInt >= LoopEnd)
661 Looping = AL_FALSE;
662 else
664 LoopStart = ALBuffer->LoopStart;
665 LoopEnd = ALBuffer->LoopEnd;
670 if(DataPosInt >= DataSize)
671 goto skipmix;
673 if(BufferListItem->next)
675 ALbuffer *NextBuf = BufferListItem->next->buffer;
676 if(NextBuf && NextBuf->size)
678 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
679 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
680 memcpy(&Data.p8[DataSize*Channels*Bytes],
681 NextBuf->data, ulExtraSamples);
684 else if(Looping)
686 ALbuffer *NextBuf = Source->queue->buffer;
687 if(NextBuf && NextBuf->size)
689 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
690 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
691 memcpy(&Data.p8[DataSize*Channels*Bytes],
692 &((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes],
693 ulExtraSamples);
696 else
697 memset(&Data.p8[DataSize*Channels*Bytes], 0, (BUFFER_PADDING*Channels*Bytes));
699 /* Figure out how many samples we can mix. */
700 DataSize64 = LoopEnd;
701 DataSize64 <<= FRACTIONBITS;
702 DataPos64 = DataPosInt;
703 DataPos64 <<= FRACTIONBITS;
704 DataPos64 += DataPosFrac;
705 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
707 BufferSize = min(BufferSize, (SamplesToDo-j));
709 if(Bytes == 4) /* 32-bit float */
710 MIX(32);
711 else if(Bytes == 2) /* signed 16-bit */
712 MIX(16);
714 skipmix:
715 /* Handle looping sources */
716 if(DataPosInt >= LoopEnd)
718 if(BufferListItem->next)
720 BufferListItem = BufferListItem->next;
721 BuffersPlayed++;
722 DataPosInt -= DataSize;
724 else if(Looping)
726 BufferListItem = Source->queue;
727 BuffersPlayed = 0;
728 if(Source->lSourceType == AL_STATIC)
729 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
730 else
731 DataPosInt -= DataSize;
733 else
735 State = AL_STOPPED;
736 BufferListItem = Source->queue;
737 BuffersPlayed = Source->BuffersInQueue;
738 DataPosInt = 0;
739 DataPosFrac = 0;
742 } while(State == AL_PLAYING && j < SamplesToDo);
744 /* Update source info */
745 Source->state = State;
746 Source->BuffersPlayed = BuffersPlayed;
747 Source->position = DataPosInt;
748 Source->position_fraction = DataPosFrac;
749 Source->Buffer = BufferListItem->buffer;
753 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
755 ALfloat (*DryBuffer)[OUTPUTCHANNELS];
756 ALfloat *ClickRemoval;
757 ALuint SamplesToDo;
758 ALeffectslot *ALEffectSlot;
759 ALCcontext **ctx, **ctx_end;
760 ALsource **src, **src_end;
761 ALfloat samp;
762 int fpuState;
763 ALuint i, j, c;
764 ALsizei e;
766 #if defined(HAVE_FESETROUND)
767 fpuState = fegetround();
768 fesetround(FE_TOWARDZERO);
769 #elif defined(HAVE__CONTROLFP)
770 fpuState = _controlfp(0, 0);
771 _controlfp(_RC_CHOP, _MCW_RC);
772 #else
773 (void)fpuState;
774 #endif
776 DryBuffer = device->DryBuffer;
777 while(size > 0)
779 /* Setup variables */
780 SamplesToDo = min(size, BUFFERSIZE);
782 /* Clear mixing buffer */
783 memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat));
785 SuspendContext(NULL);
786 ctx = device->Contexts;
787 ctx_end = ctx + device->NumContexts;
788 while(ctx != ctx_end)
790 SuspendContext(*ctx);
792 src = (*ctx)->ActiveSources;
793 src_end = src + (*ctx)->ActiveSourceCount;
794 while(src != src_end)
796 if((*src)->state != AL_PLAYING)
798 --((*ctx)->ActiveSourceCount);
799 *src = *(--src_end);
800 continue;
803 if((*src)->NeedsUpdate)
805 ALsource_Update(*src, *ctx);
806 (*src)->NeedsUpdate = AL_FALSE;
809 ALsource_Mix(*src, SamplesToDo, DryBuffer,
810 device->ClickRemoval, device->PendingClicks);
811 src++;
814 /* effect slot processing */
815 for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
817 ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
819 ClickRemoval = ALEffectSlot->ClickRemoval;
820 for(i = 0;i < SamplesToDo;i++)
822 ClickRemoval[0] -= ClickRemoval[0] / 256.0f;
823 ALEffectSlot->WetBuffer[i] += ClickRemoval[0];
825 for(i = 0;i < 1;i++)
827 ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
828 ALEffectSlot->PendingClicks[i] = 0.0f;
831 ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer);
833 for(i = 0;i < SamplesToDo;i++)
834 ALEffectSlot->WetBuffer[i] = 0.0f;
837 ProcessContext(*ctx);
838 ctx++;
840 device->SamplesPlayed += SamplesToDo;
841 ProcessContext(NULL);
843 //Post processing loop
844 ClickRemoval = device->ClickRemoval;
845 for(i = 0;i < SamplesToDo;i++)
847 for(c = 0;c < OUTPUTCHANNELS;c++)
849 ClickRemoval[c] -= ClickRemoval[c] / 256.0f;
850 DryBuffer[i][c] += ClickRemoval[c];
853 for(i = 0;i < OUTPUTCHANNELS;i++)
855 device->ClickRemoval[i] += device->PendingClicks[i];
856 device->PendingClicks[i] = 0.0f;
859 switch(device->Format)
861 #define DO_WRITE(T, func, N, ...) do { \
862 const Channel chans[] = { \
863 __VA_ARGS__ \
864 }; \
865 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
866 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
867 const ALuint *ChanMap = device->DevChannels; \
869 for(i = 0;i < SamplesToDo;i++) \
871 for(j = 0;j < N;j++) \
873 samp = 0.0f; \
874 for(c = 0;c < OUTPUTCHANNELS;c++) \
875 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
876 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
878 buffer = ((T*)buffer) + N; \
880 } while(0)
882 #define CHECK_WRITE_FORMAT(bits, T, func) \
883 case AL_FORMAT_MONO##bits: \
884 DO_WRITE(T, func, 1, FRONT_CENTER); \
885 break; \
886 case AL_FORMAT_STEREO##bits: \
887 if(device->Bs2b) \
889 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
890 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
891 const ALuint *ChanMap = device->DevChannels; \
893 for(i = 0;i < SamplesToDo;i++) \
895 float samples[2] = { 0.0f, 0.0f }; \
896 for(c = 0;c < OUTPUTCHANNELS;c++) \
898 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
899 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
901 bs2b_cross_feed(device->Bs2b, samples); \
902 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
903 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
904 buffer = ((T*)buffer) + 2; \
907 else \
908 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
909 break; \
910 case AL_FORMAT_QUAD##bits: \
911 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
912 BACK_LEFT, BACK_RIGHT); \
913 break; \
914 case AL_FORMAT_51CHN##bits: \
915 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
916 FRONT_CENTER, LFE, \
917 BACK_LEFT, BACK_RIGHT); \
918 break; \
919 case AL_FORMAT_61CHN##bits: \
920 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
921 FRONT_CENTER, LFE, BACK_CENTER, \
922 SIDE_LEFT, SIDE_RIGHT); \
923 break; \
924 case AL_FORMAT_71CHN##bits: \
925 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
926 FRONT_CENTER, LFE, \
927 BACK_LEFT, BACK_RIGHT, \
928 SIDE_LEFT, SIDE_RIGHT); \
929 break;
931 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
932 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
933 CHECK_WRITE_FORMAT(8, ALubyte, aluF2UB)
934 CHECK_WRITE_FORMAT(16, ALshort, aluF2S)
935 CHECK_WRITE_FORMAT(32, ALfloat, aluF2F)
936 #undef AL_FORMAT_STEREO32
937 #undef AL_FORMAT_MONO32
938 #undef CHECK_WRITE_FORMAT
939 #undef DO_WRITE
941 default:
942 break;
945 size -= SamplesToDo;
948 #if defined(HAVE_FESETROUND)
949 fesetround(fpuState);
950 #elif defined(HAVE__CONTROLFP)
951 _controlfp(fpuState, 0xfffff);
952 #endif