Fix reverb with UHJ encoding
[openal-soft.git] / Alc / mixer.c
blob779d69e00969027b380f20b06560260184faf894
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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"
38 #include "mixer_defs.h"
41 static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
42 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
44 extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
46 alignas(16) union ResamplerCoeffs ResampleCoeffs;
49 enum Resampler {
50 PointResampler,
51 LinearResampler,
52 FIR4Resampler,
53 FIR8Resampler,
54 BSincResampler,
56 ResamplerDefault = LinearResampler
59 /* FIR8 requires 3 extra samples before the current position, and 4 after. */
60 static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!");
61 static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!");
64 static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
65 static MixerFunc MixSamples = Mix_C;
66 static ResamplerFunc ResampleSamples = Resample_point32_C;
68 static inline HrtfMixerFunc SelectHrtfMixer(void)
70 #ifdef HAVE_SSE
71 if((CPUCapFlags&CPU_CAP_SSE))
72 return MixHrtf_SSE;
73 #endif
74 #ifdef HAVE_NEON
75 if((CPUCapFlags&CPU_CAP_NEON))
76 return MixHrtf_Neon;
77 #endif
79 return MixHrtf_C;
82 static inline MixerFunc SelectMixer(void)
84 #ifdef HAVE_SSE
85 if((CPUCapFlags&CPU_CAP_SSE))
86 return Mix_SSE;
87 #endif
88 #ifdef HAVE_NEON
89 if((CPUCapFlags&CPU_CAP_NEON))
90 return Mix_Neon;
91 #endif
93 return Mix_C;
96 static inline ResamplerFunc SelectResampler(enum Resampler resampler)
98 switch(resampler)
100 case PointResampler:
101 return Resample_point32_C;
102 case LinearResampler:
103 #ifdef HAVE_SSE4_1
104 if((CPUCapFlags&CPU_CAP_SSE4_1))
105 return Resample_lerp32_SSE41;
106 #endif
107 #ifdef HAVE_SSE2
108 if((CPUCapFlags&CPU_CAP_SSE2))
109 return Resample_lerp32_SSE2;
110 #endif
111 return Resample_lerp32_C;
112 case FIR4Resampler:
113 #ifdef HAVE_SSE4_1
114 if((CPUCapFlags&CPU_CAP_SSE4_1))
115 return Resample_fir4_32_SSE41;
116 #endif
117 #ifdef HAVE_SSE3
118 if((CPUCapFlags&CPU_CAP_SSE3))
119 return Resample_fir4_32_SSE3;
120 #endif
121 return Resample_fir4_32_C;
122 case FIR8Resampler:
123 #ifdef HAVE_SSE4_1
124 if((CPUCapFlags&CPU_CAP_SSE4_1))
125 return Resample_fir8_32_SSE41;
126 #endif
127 #ifdef HAVE_SSE3
128 if((CPUCapFlags&CPU_CAP_SSE3))
129 return Resample_fir8_32_SSE3;
130 #endif
131 return Resample_fir8_32_C;
132 case BSincResampler:
133 #ifdef HAVE_SSE
134 if((CPUCapFlags&CPU_CAP_SSE))
135 return Resample_bsinc32_SSE;
136 #endif
137 return Resample_bsinc32_C;
140 return Resample_point32_C;
144 /* The sinc resampler makes use of a Kaiser window to limit the needed sample
145 * points to 4 and 8, respectively.
148 #ifndef M_PI
149 #define M_PI (3.14159265358979323846)
150 #endif
151 static inline double Sinc(double x)
153 if(x == 0.0) return 1.0;
154 return sin(x*M_PI) / (x*M_PI);
157 /* The zero-order modified Bessel function of the first kind, used for the
158 * Kaiser window.
160 * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
161 * = sum_{k=0}^inf ((x / 2)^k / k!)^2
163 static double BesselI_0(double x)
165 double term, sum, x2, y, last_sum;
166 int k;
168 /* Start at k=1 since k=0 is trivial. */
169 term = 1.0;
170 sum = 1.0;
171 x2 = x / 2.0;
172 k = 1;
174 /* Let the integration converge until the term of the sum is no longer
175 * significant.
177 do {
178 y = x2 / k;
179 k ++;
180 last_sum = sum;
181 term *= y * y;
182 sum += term;
183 } while(sum != last_sum);
184 return sum;
187 /* Calculate a Kaiser window from the given beta value and a normalized k
188 * [-1, 1].
190 * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
191 * { 0, elsewhere.
193 * Where k can be calculated as:
195 * k = i / l, where -l <= i <= l.
197 * or:
199 * k = 2 i / M - 1, where 0 <= i <= M.
201 static inline double Kaiser(double b, double k)
203 if(k <= -1.0 || k >= 1.0) return 0.0;
204 return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b);
207 static inline double CalcKaiserBeta(double rejection)
209 if(rejection > 50.0)
210 return 0.1102 * (rejection - 8.7);
211 if(rejection >= 21.0)
212 return (0.5842 * pow(rejection - 21.0, 0.4)) +
213 (0.07886 * (rejection - 21.0));
214 return 0.0;
217 static float SincKaiser(double r, double x)
219 /* Limit rippling to -60dB. */
220 return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x));
224 void aluInitMixer(void)
226 enum Resampler resampler = ResamplerDefault;
227 const char *str;
228 ALuint i;
230 if(ConfigValueStr(NULL, NULL, "resampler", &str))
232 if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
233 resampler = PointResampler;
234 else if(strcasecmp(str, "linear") == 0)
235 resampler = LinearResampler;
236 else if(strcasecmp(str, "sinc4") == 0)
237 resampler = FIR4Resampler;
238 else if(strcasecmp(str, "sinc8") == 0)
239 resampler = FIR8Resampler;
240 else if(strcasecmp(str, "bsinc") == 0)
241 resampler = BSincResampler;
242 else if(strcasecmp(str, "cubic") == 0)
244 WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
245 resampler = FIR4Resampler;
247 else
249 char *end;
250 long n = strtol(str, &end, 0);
251 if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
252 resampler = n;
253 else
254 WARN("Invalid resampler: %s\n", str);
258 if(resampler == FIR8Resampler)
259 for(i = 0;i < FRACTIONONE;i++)
261 ALdouble mu = (ALdouble)i / FRACTIONONE;
262 ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0);
263 ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0);
264 ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0);
265 ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0);
266 ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0);
267 ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0);
268 ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0);
269 ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0);
271 else if(resampler == FIR4Resampler)
272 for(i = 0;i < FRACTIONONE;i++)
274 ALdouble mu = (ALdouble)i / FRACTIONONE;
275 ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0);
276 ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0);
277 ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0);
278 ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0);
281 MixHrtfSamples = SelectHrtfMixer();
282 MixSamples = SelectMixer();
283 ResampleSamples = SelectResampler(resampler);
287 static inline ALfloat Sample_ALbyte(ALbyte val)
288 { return val * (1.0f/127.0f); }
290 static inline ALfloat Sample_ALshort(ALshort val)
291 { return val * (1.0f/32767.0f); }
293 static inline ALfloat Sample_ALfloat(ALfloat val)
294 { return val; }
296 #define DECL_TEMPLATE(T) \
297 static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
299 ALuint i; \
300 for(i = 0;i < samples;i++) \
301 dst[i] = Sample_##T(src[i*srcstep]); \
304 DECL_TEMPLATE(ALbyte)
305 DECL_TEMPLATE(ALshort)
306 DECL_TEMPLATE(ALfloat)
308 #undef DECL_TEMPLATE
310 static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
312 switch(srctype)
314 case FmtByte:
315 Load_ALbyte(dst, src, srcstep, samples);
316 break;
317 case FmtShort:
318 Load_ALshort(dst, src, srcstep, samples);
319 break;
320 case FmtFloat:
321 Load_ALfloat(dst, src, srcstep, samples);
322 break;
326 static inline void SilenceSamples(ALfloat *dst, ALuint samples)
328 ALuint i;
329 for(i = 0;i < samples;i++)
330 dst[i] = 0.0f;
334 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
335 ALfloat *restrict dst, const ALfloat *restrict src,
336 ALuint numsamples, enum ActiveFilters type)
338 ALuint i;
339 switch(type)
341 case AF_None:
342 ALfilterState_processPassthru(lpfilter, src, numsamples);
343 ALfilterState_processPassthru(hpfilter, src, numsamples);
344 break;
346 case AF_LowPass:
347 ALfilterState_process(lpfilter, dst, src, numsamples);
348 ALfilterState_processPassthru(hpfilter, dst, numsamples);
349 return dst;
350 case AF_HighPass:
351 ALfilterState_processPassthru(lpfilter, src, numsamples);
352 ALfilterState_process(hpfilter, dst, src, numsamples);
353 return dst;
355 case AF_BandPass:
356 for(i = 0;i < numsamples;)
358 ALfloat temp[256];
359 ALuint todo = minu(256, numsamples-i);
361 ALfilterState_process(lpfilter, temp, src+i, todo);
362 ALfilterState_process(hpfilter, dst+i, temp, todo);
363 i += todo;
365 return dst;
367 return src;
371 ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
373 ResamplerFunc Resample;
374 ALbufferlistitem *BufferListItem;
375 ALuint DataPosInt, DataPosFrac;
376 ALboolean Looping;
377 ALuint increment;
378 ALenum State;
379 ALuint OutPos;
380 ALuint NumChannels;
381 ALuint SampleSize;
382 ALint64 DataSize64;
383 ALuint IrSize;
384 ALuint chan, j;
386 /* Get source info */
387 State = Source->state;
388 BufferListItem = ATOMIC_LOAD(&Source->current_buffer);
389 DataPosInt = Source->position;
390 DataPosFrac = Source->position_fraction;
391 Looping = Source->Looping;
392 NumChannels = Source->NumChannels;
393 SampleSize = Source->SampleSize;
394 increment = voice->Step;
396 IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0);
398 Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
399 Resample_copy32_C : ResampleSamples);
401 OutPos = 0;
402 do {
403 ALuint SrcBufferSize, DstBufferSize;
404 ALuint Counter;
405 ALfloat Delta;
407 if(!voice->Moving)
409 Counter = 0;
410 Delta = 0.0f;
412 else
414 Counter = SamplesToDo - OutPos;
415 Delta = 1.0f / (ALfloat)Counter;
418 /* Figure out how many buffer samples will be needed */
419 DataSize64 = SamplesToDo-OutPos;
420 DataSize64 *= increment;
421 DataSize64 += DataPosFrac+FRACTIONMASK;
422 DataSize64 >>= FRACTIONBITS;
423 DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
425 SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
427 /* Figure out how many samples we can actually mix from this. */
428 DataSize64 = SrcBufferSize;
429 DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
430 DataSize64 <<= FRACTIONBITS;
431 DataSize64 -= DataPosFrac;
433 DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
434 DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
436 /* Some mixers like having a multiple of 4, so try to give that unless
437 * this is the last update. */
438 if(OutPos+DstBufferSize < SamplesToDo)
439 DstBufferSize &= ~3;
441 for(chan = 0;chan < NumChannels;chan++)
443 const ALfloat *ResampledData;
444 ALfloat *SrcData = Device->SourceData;
445 ALuint SrcDataSize;
447 /* Load the previous samples into the source data first. */
448 memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
449 SrcDataSize = MAX_PRE_SAMPLES;
451 if(Source->SourceType == AL_STATIC)
453 const ALbuffer *ALBuffer = BufferListItem->buffer;
454 const ALubyte *Data = ALBuffer->data;
455 ALuint DataSize;
456 ALuint pos;
458 /* Offset buffer data to current channel */
459 Data += chan*SampleSize;
461 /* If current pos is beyond the loop range, do not loop */
462 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
464 Looping = AL_FALSE;
466 /* Load what's left to play from the source buffer, and
467 * clear the rest of the temp buffer */
468 pos = DataPosInt;
469 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
471 LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
472 NumChannels, ALBuffer->FmtType, DataSize);
473 SrcDataSize += DataSize;
475 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
476 SrcDataSize += SrcBufferSize - SrcDataSize;
478 else
480 ALuint LoopStart = ALBuffer->LoopStart;
481 ALuint LoopEnd = ALBuffer->LoopEnd;
483 /* Load what's left of this loop iteration, then load
484 * repeats of the loop section */
485 pos = DataPosInt;
486 DataSize = LoopEnd - pos;
487 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
489 LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
490 NumChannels, ALBuffer->FmtType, DataSize);
491 SrcDataSize += DataSize;
493 DataSize = LoopEnd-LoopStart;
494 while(SrcBufferSize > SrcDataSize)
496 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
498 LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
499 NumChannels, ALBuffer->FmtType, DataSize);
500 SrcDataSize += DataSize;
504 else
506 /* Crawl the buffer queue to fill in the temp buffer */
507 ALbufferlistitem *tmpiter = BufferListItem;
508 ALuint pos = DataPosInt;
510 while(tmpiter && SrcBufferSize > SrcDataSize)
512 const ALbuffer *ALBuffer;
513 if((ALBuffer=tmpiter->buffer) != NULL)
515 const ALubyte *Data = ALBuffer->data;
516 ALuint DataSize = ALBuffer->SampleLen;
518 /* Skip the data already played */
519 if(DataSize <= pos)
520 pos -= DataSize;
521 else
523 Data += (pos*NumChannels + chan)*SampleSize;
524 DataSize -= pos;
525 pos -= pos;
527 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
528 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
529 ALBuffer->FmtType, DataSize);
530 SrcDataSize += DataSize;
533 tmpiter = tmpiter->next;
534 if(!tmpiter && Looping)
535 tmpiter = ATOMIC_LOAD(&Source->queue);
536 else if(!tmpiter)
538 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
539 SrcDataSize += SrcBufferSize - SrcDataSize;
544 /* Store the last source samples used for next time. */
545 memcpy(voice->PrevSamples[chan],
546 &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
547 MAX_PRE_SAMPLES*sizeof(ALfloat)
550 /* Now resample, then filter and mix to the appropriate outputs. */
551 ResampledData = Resample(&voice->SincState,
552 &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
553 Device->ResampledData, DstBufferSize
556 DirectParams *parms = &voice->Direct;
557 const ALfloat *samples;
559 samples = DoFilters(
560 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
561 Device->FilteredData, ResampledData, DstBufferSize,
562 parms->Filters[chan].ActiveType
564 if(!voice->IsHrtf)
566 ALfloat *restrict currents = parms->Gains[chan].Current;
567 const ALfloat *targets = parms->Gains[chan].Target;
568 MixGains gains[MAX_OUTPUT_CHANNELS];
570 if(!Counter)
572 for(j = 0;j < parms->OutChannels;j++)
574 gains[j].Target = targets[j];
575 gains[j].Current = gains[j].Target;
576 gains[j].Step = 0.0f;
579 else
581 for(j = 0;j < parms->OutChannels;j++)
583 ALfloat diff;
584 gains[j].Target = targets[j];
585 gains[j].Current = currents[j];
586 diff = gains[j].Target - gains[j].Current;
587 if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD)
588 gains[j].Step = diff * Delta;
589 else
591 gains[j].Current = gains[j].Target;
592 gains[j].Step = 0.0f;
597 MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains,
598 Counter, OutPos, DstBufferSize);
600 for(j = 0;j < parms->OutChannels;j++)
601 currents[j] = gains[j].Current;
603 else
605 MixHrtfParams hrtfparams;
606 if(!Counter)
608 parms->Hrtf[chan].Current = parms->Hrtf[chan].Target;
609 for(j = 0;j < HRIR_LENGTH;j++)
611 hrtfparams.Steps.Coeffs[j][0] = 0.0f;
612 hrtfparams.Steps.Coeffs[j][1] = 0.0f;
614 hrtfparams.Steps.Delay[0] = 0;
615 hrtfparams.Steps.Delay[1] = 0;
617 else
619 ALfloat coeffdiff;
620 ALint delaydiff;
621 for(j = 0;j < IrSize;j++)
623 coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][0] - parms->Hrtf[chan].Current.Coeffs[j][0];
624 hrtfparams.Steps.Coeffs[j][0] = coeffdiff * Delta;
625 coeffdiff = parms->Hrtf[chan].Target.Coeffs[j][1] - parms->Hrtf[chan].Current.Coeffs[j][1];
626 hrtfparams.Steps.Coeffs[j][1] = coeffdiff * Delta;
628 delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[0] - parms->Hrtf[chan].Current.Delay[0]);
629 hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * Delta);
630 delaydiff = (ALint)(parms->Hrtf[chan].Target.Delay[1] - parms->Hrtf[chan].Current.Delay[1]);
631 hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * Delta);
633 hrtfparams.Target = &parms->Hrtf[chan].Target;
634 hrtfparams.Current = &parms->Hrtf[chan].Current;
636 MixHrtfSamples(parms->OutBuffer, samples, Counter, voice->Offset,
637 OutPos, IrSize, &hrtfparams, &parms->Hrtf[chan].State,
638 DstBufferSize);
642 for(j = 0;j < Device->NumAuxSends;j++)
644 SendParams *parms = &voice->Send[j];
645 ALfloat *restrict currents = parms->Gains[chan].Current;
646 const ALfloat *targets = parms->Gains[chan].Target;
647 MixGains gains[MAX_OUTPUT_CHANNELS];
648 const ALfloat *samples;
650 if(!parms->OutBuffer)
651 continue;
653 samples = DoFilters(
654 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
655 Device->FilteredData, ResampledData, DstBufferSize,
656 parms->Filters[chan].ActiveType
659 if(!Counter)
661 for(j = 0;j < parms->OutChannels;j++)
663 gains[j].Target = targets[j];
664 gains[j].Current = gains[j].Target;
665 gains[j].Step = 0.0f;
668 else
670 for(j = 0;j < parms->OutChannels;j++)
672 ALfloat diff;
673 gains[j].Target = targets[j];
674 gains[j].Current = currents[j];
675 diff = gains[j].Target - gains[j].Current;
676 if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD)
677 gains[j].Step = diff * Delta;
678 else
680 gains[j].Current = gains[j].Target;
681 gains[j].Step = 0.0f;
686 MixSamples(samples, parms->OutChannels, parms->OutBuffer, gains,
687 Counter, OutPos, DstBufferSize);
689 for(j = 0;j < parms->OutChannels;j++)
690 currents[j] = gains[j].Current;
693 /* Update positions */
694 DataPosFrac += increment*DstBufferSize;
695 DataPosInt += DataPosFrac>>FRACTIONBITS;
696 DataPosFrac &= FRACTIONMASK;
698 OutPos += DstBufferSize;
699 voice->Offset += DstBufferSize;
701 /* Handle looping sources */
702 while(1)
704 const ALbuffer *ALBuffer;
705 ALuint DataSize = 0;
706 ALuint LoopStart = 0;
707 ALuint LoopEnd = 0;
709 if((ALBuffer=BufferListItem->buffer) != NULL)
711 DataSize = ALBuffer->SampleLen;
712 LoopStart = ALBuffer->LoopStart;
713 LoopEnd = ALBuffer->LoopEnd;
714 if(LoopEnd > DataPosInt)
715 break;
718 if(Looping && Source->SourceType == AL_STATIC)
720 assert(LoopEnd > LoopStart);
721 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
722 break;
725 if(DataSize > DataPosInt)
726 break;
728 if(!(BufferListItem=BufferListItem->next))
730 if(Looping)
731 BufferListItem = ATOMIC_LOAD(&Source->queue);
732 else
734 State = AL_STOPPED;
735 BufferListItem = NULL;
736 DataPosInt = 0;
737 DataPosFrac = 0;
738 break;
742 DataPosInt -= DataSize;
744 } while(State == AL_PLAYING && OutPos < SamplesToDo);
746 voice->Moving = AL_TRUE;
748 /* Update source info */
749 Source->state = State;
750 ATOMIC_STORE(&Source->current_buffer, BufferListItem);
751 Source->position = DataPosInt;
752 Source->position_fraction = DataPosFrac;