Make the source state atomic
[openal-soft.git] / Alc / mixer.c
blob179c028e0ff8a607a33ce4fb5997df8b3a7fae45
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, ALint increment, ALuint *restrict frac_arr, ALint *restrict pos_arr, ALsizei 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 MixerFunc MixSamples = Mix_C;
65 static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
66 static ResamplerFunc ResampleSamples = Resample_point32_C;
68 MixerFunc SelectMixer(void)
70 #ifdef HAVE_SSE
71 if((CPUCapFlags&CPU_CAP_SSE))
72 return Mix_SSE;
73 #endif
74 #ifdef HAVE_NEON
75 if((CPUCapFlags&CPU_CAP_NEON))
76 return Mix_Neon;
77 #endif
79 return Mix_C;
82 RowMixerFunc SelectRowMixer(void)
84 #ifdef HAVE_SSE
85 if((CPUCapFlags&CPU_CAP_SSE))
86 return MixRow_SSE;
87 #endif
88 #ifdef HAVE_NEON
89 if((CPUCapFlags&CPU_CAP_NEON))
90 return MixRow_Neon;
91 #endif
92 return MixRow_C;
95 static inline HrtfMixerFunc SelectHrtfMixer(void)
97 #ifdef HAVE_SSE
98 if((CPUCapFlags&CPU_CAP_SSE))
99 return MixHrtf_SSE;
100 #endif
101 #ifdef HAVE_NEON
102 if((CPUCapFlags&CPU_CAP_NEON))
103 return MixHrtf_Neon;
104 #endif
106 return MixHrtf_C;
109 static inline ResamplerFunc SelectResampler(enum Resampler resampler)
111 switch(resampler)
113 case PointResampler:
114 return Resample_point32_C;
115 case LinearResampler:
116 #ifdef HAVE_NEON
117 if((CPUCapFlags&CPU_CAP_NEON))
118 return Resample_lerp32_Neon;
119 #endif
120 #ifdef HAVE_SSE4_1
121 if((CPUCapFlags&CPU_CAP_SSE4_1))
122 return Resample_lerp32_SSE41;
123 #endif
124 #ifdef HAVE_SSE2
125 if((CPUCapFlags&CPU_CAP_SSE2))
126 return Resample_lerp32_SSE2;
127 #endif
128 return Resample_lerp32_C;
129 case FIR4Resampler:
130 #ifdef HAVE_NEON
131 if((CPUCapFlags&CPU_CAP_NEON))
132 return Resample_fir4_32_Neon;
133 #endif
134 #ifdef HAVE_SSE4_1
135 if((CPUCapFlags&CPU_CAP_SSE4_1))
136 return Resample_fir4_32_SSE41;
137 #endif
138 #ifdef HAVE_SSE3
139 if((CPUCapFlags&CPU_CAP_SSE3))
140 return Resample_fir4_32_SSE3;
141 #endif
142 return Resample_fir4_32_C;
143 case FIR8Resampler:
144 #ifdef HAVE_NEON
145 if((CPUCapFlags&CPU_CAP_NEON))
146 return Resample_fir8_32_Neon;
147 #endif
148 #ifdef HAVE_SSE4_1
149 if((CPUCapFlags&CPU_CAP_SSE4_1))
150 return Resample_fir8_32_SSE41;
151 #endif
152 #ifdef HAVE_SSE3
153 if((CPUCapFlags&CPU_CAP_SSE3))
154 return Resample_fir8_32_SSE3;
155 #endif
156 return Resample_fir8_32_C;
157 case BSincResampler:
158 #ifdef HAVE_NEON
159 if((CPUCapFlags&CPU_CAP_NEON))
160 return Resample_bsinc32_Neon;
161 #endif
162 #ifdef HAVE_SSE
163 if((CPUCapFlags&CPU_CAP_SSE))
164 return Resample_bsinc32_SSE;
165 #endif
166 return Resample_bsinc32_C;
169 return Resample_point32_C;
173 /* The sinc resampler makes use of a Kaiser window to limit the needed sample
174 * points to 4 and 8, respectively.
177 #ifndef M_PI
178 #define M_PI (3.14159265358979323846)
179 #endif
180 static inline double Sinc(double x)
182 if(x == 0.0) return 1.0;
183 return sin(x*M_PI) / (x*M_PI);
186 /* The zero-order modified Bessel function of the first kind, used for the
187 * Kaiser window.
189 * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
190 * = sum_{k=0}^inf ((x / 2)^k / k!)^2
192 static double BesselI_0(double x)
194 double term, sum, x2, y, last_sum;
195 int k;
197 /* Start at k=1 since k=0 is trivial. */
198 term = 1.0;
199 sum = 1.0;
200 x2 = x / 2.0;
201 k = 1;
203 /* Let the integration converge until the term of the sum is no longer
204 * significant.
206 do {
207 y = x2 / k;
208 k ++;
209 last_sum = sum;
210 term *= y * y;
211 sum += term;
212 } while(sum != last_sum);
213 return sum;
216 /* Calculate a Kaiser window from the given beta value and a normalized k
217 * [-1, 1].
219 * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
220 * { 0, elsewhere.
222 * Where k can be calculated as:
224 * k = i / l, where -l <= i <= l.
226 * or:
228 * k = 2 i / M - 1, where 0 <= i <= M.
230 static inline double Kaiser(double b, double k)
232 if(k <= -1.0 || k >= 1.0) return 0.0;
233 return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b);
236 static inline double CalcKaiserBeta(double rejection)
238 if(rejection > 50.0)
239 return 0.1102 * (rejection - 8.7);
240 if(rejection >= 21.0)
241 return (0.5842 * pow(rejection - 21.0, 0.4)) +
242 (0.07886 * (rejection - 21.0));
243 return 0.0;
246 static float SincKaiser(double r, double x)
248 /* Limit rippling to -60dB. */
249 return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x));
253 void aluInitMixer(void)
255 enum Resampler resampler = ResamplerDefault;
256 const char *str;
257 ALuint i;
259 if(ConfigValueStr(NULL, NULL, "resampler", &str))
261 if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
262 resampler = PointResampler;
263 else if(strcasecmp(str, "linear") == 0)
264 resampler = LinearResampler;
265 else if(strcasecmp(str, "sinc4") == 0)
266 resampler = FIR4Resampler;
267 else if(strcasecmp(str, "sinc8") == 0)
268 resampler = FIR8Resampler;
269 else if(strcasecmp(str, "bsinc") == 0)
270 resampler = BSincResampler;
271 else if(strcasecmp(str, "cubic") == 0)
273 WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
274 resampler = FIR4Resampler;
276 else
278 char *end;
279 long n = strtol(str, &end, 0);
280 if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
281 resampler = n;
282 else
283 WARN("Invalid resampler: %s\n", str);
287 if(resampler == FIR8Resampler)
288 for(i = 0;i < FRACTIONONE;i++)
290 ALdouble mu = (ALdouble)i / FRACTIONONE;
291 ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0);
292 ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0);
293 ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0);
294 ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0);
295 ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0);
296 ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0);
297 ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0);
298 ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0);
300 else if(resampler == FIR4Resampler)
301 for(i = 0;i < FRACTIONONE;i++)
303 ALdouble mu = (ALdouble)i / FRACTIONONE;
304 ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0);
305 ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0);
306 ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0);
307 ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0);
310 MixHrtfSamples = SelectHrtfMixer();
311 MixSamples = SelectMixer();
312 ResampleSamples = SelectResampler(resampler);
316 static inline ALfloat Sample_ALbyte(ALbyte val)
317 { return val * (1.0f/127.0f); }
319 static inline ALfloat Sample_ALshort(ALshort val)
320 { return val * (1.0f/32767.0f); }
322 static inline ALfloat Sample_ALfloat(ALfloat val)
323 { return val; }
325 #define DECL_TEMPLATE(T) \
326 static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\
328 ALsizei i; \
329 for(i = 0;i < samples;i++) \
330 dst[i] = Sample_##T(src[i*srcstep]); \
333 DECL_TEMPLATE(ALbyte)
334 DECL_TEMPLATE(ALshort)
335 DECL_TEMPLATE(ALfloat)
337 #undef DECL_TEMPLATE
339 static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum FmtType srctype, ALsizei samples)
341 switch(srctype)
343 case FmtByte:
344 Load_ALbyte(dst, src, srcstep, samples);
345 break;
346 case FmtShort:
347 Load_ALshort(dst, src, srcstep, samples);
348 break;
349 case FmtFloat:
350 Load_ALfloat(dst, src, srcstep, samples);
351 break;
355 static inline void SilenceSamples(ALfloat *dst, ALsizei samples)
357 ALsizei i;
358 for(i = 0;i < samples;i++)
359 dst[i] = 0.0f;
363 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
364 ALfloat *restrict dst, const ALfloat *restrict src,
365 ALsizei numsamples, enum ActiveFilters type)
367 ALsizei i;
368 switch(type)
370 case AF_None:
371 ALfilterState_processPassthru(lpfilter, src, numsamples);
372 ALfilterState_processPassthru(hpfilter, src, numsamples);
373 break;
375 case AF_LowPass:
376 ALfilterState_process(lpfilter, dst, src, numsamples);
377 ALfilterState_processPassthru(hpfilter, dst, numsamples);
378 return dst;
379 case AF_HighPass:
380 ALfilterState_processPassthru(lpfilter, src, numsamples);
381 ALfilterState_process(hpfilter, dst, src, numsamples);
382 return dst;
384 case AF_BandPass:
385 for(i = 0;i < numsamples;)
387 ALfloat temp[256];
388 ALsizei todo = mini(256, numsamples-i);
390 ALfilterState_process(lpfilter, temp, src+i, todo);
391 ALfilterState_process(hpfilter, dst+i, temp, todo);
392 i += todo;
394 return dst;
396 return src;
400 void MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo)
402 ResamplerFunc Resample;
403 ALbufferlistitem *BufferListItem;
404 ALuint DataPosInt, DataPosFrac;
405 ALboolean Looping;
406 ALint increment;
407 ALenum State;
408 ALsizei OutPos;
409 ALsizei NumChannels;
410 ALsizei SampleSize;
411 ALint64 DataSize64;
412 ALsizei Counter;
413 ALsizei IrSize;
414 ALsizei chan, j;
415 ALuint send;
417 /* Get source info */
418 State = AL_PLAYING; /* Only called while playing. */
419 BufferListItem = ATOMIC_LOAD(&Source->current_buffer, almemory_order_acquire);
420 DataPosInt = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
421 DataPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
422 Looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
423 NumChannels = Source->NumChannels;
424 SampleSize = Source->SampleSize;
425 increment = voice->Step;
427 IrSize = (Device->Hrtf.Handle ? Device->Hrtf.Handle->irSize : 0);
429 Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
430 Resample_copy32_C : ResampleSamples);
432 Counter = voice->Moving ? SamplesToDo : 0;
433 OutPos = 0;
434 do {
435 ALsizei SrcBufferSize, DstBufferSize;
437 /* Figure out how many buffer samples will be needed */
438 DataSize64 = SamplesToDo-OutPos;
439 DataSize64 *= increment;
440 DataSize64 += DataPosFrac+FRACTIONMASK;
441 DataSize64 >>= FRACTIONBITS;
442 DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
444 SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
446 /* Figure out how many samples we can actually mix from this. */
447 DataSize64 = SrcBufferSize;
448 DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
449 DataSize64 <<= FRACTIONBITS;
450 DataSize64 -= DataPosFrac;
452 DstBufferSize = (ALsizei)((DataSize64+(increment-1)) / increment);
453 DstBufferSize = mini(DstBufferSize, (SamplesToDo-OutPos));
455 /* Some mixers like having a multiple of 4, so try to give that unless
456 * this is the last update. */
457 if(OutPos+DstBufferSize < SamplesToDo)
458 DstBufferSize &= ~3;
460 for(chan = 0;chan < NumChannels;chan++)
462 const ALfloat *ResampledData;
463 ALfloat *SrcData = Device->SourceData;
464 ALsizei SrcDataSize;
466 /* Load the previous samples into the source data first. */
467 memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
468 SrcDataSize = MAX_PRE_SAMPLES;
470 if(Source->SourceType == AL_STATIC)
472 const ALbuffer *ALBuffer = BufferListItem->buffer;
473 const ALubyte *Data = ALBuffer->data;
474 ALsizei DataSize;
476 /* Offset buffer data to current channel */
477 Data += chan*SampleSize;
479 /* If current pos is beyond the loop range, do not loop */
480 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
482 Looping = AL_FALSE;
484 /* Load what's left to play from the source buffer, and
485 * clear the rest of the temp buffer */
486 DataSize = minu(SrcBufferSize - SrcDataSize,
487 ALBuffer->SampleLen - DataPosInt);
489 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
490 NumChannels, ALBuffer->FmtType, DataSize);
491 SrcDataSize += DataSize;
493 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
494 SrcDataSize += SrcBufferSize - SrcDataSize;
496 else
498 ALsizei LoopStart = ALBuffer->LoopStart;
499 ALsizei LoopEnd = ALBuffer->LoopEnd;
501 /* Load what's left of this loop iteration, then load
502 * repeats of the loop section */
503 DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt);
505 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
506 NumChannels, ALBuffer->FmtType, DataSize);
507 SrcDataSize += DataSize;
509 DataSize = LoopEnd-LoopStart;
510 while(SrcBufferSize > SrcDataSize)
512 DataSize = mini(SrcBufferSize - SrcDataSize, DataSize);
514 LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
515 NumChannels, ALBuffer->FmtType, DataSize);
516 SrcDataSize += DataSize;
520 else
522 /* Crawl the buffer queue to fill in the temp buffer */
523 ALbufferlistitem *tmpiter = BufferListItem;
524 ALuint pos = DataPosInt;
526 while(tmpiter && SrcBufferSize > SrcDataSize)
528 const ALbuffer *ALBuffer;
529 if((ALBuffer=tmpiter->buffer) != NULL)
531 const ALubyte *Data = ALBuffer->data;
532 ALuint DataSize = ALBuffer->SampleLen;
534 /* Skip the data already played */
535 if(DataSize <= pos)
536 pos -= DataSize;
537 else
539 Data += (pos*NumChannels + chan)*SampleSize;
540 DataSize -= pos;
541 pos -= pos;
543 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
544 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
545 ALBuffer->FmtType, DataSize);
546 SrcDataSize += DataSize;
549 tmpiter = tmpiter->next;
550 if(!tmpiter && Looping)
551 tmpiter = ATOMIC_LOAD(&Source->queue, almemory_order_acquire);
552 else if(!tmpiter)
554 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
555 SrcDataSize += SrcBufferSize - SrcDataSize;
560 /* Store the last source samples used for next time. */
561 memcpy(voice->PrevSamples[chan],
562 &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
563 MAX_PRE_SAMPLES*sizeof(ALfloat)
566 /* Now resample, then filter and mix to the appropriate outputs. */
567 ResampledData = Resample(&voice->ResampleState,
568 &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
569 Device->ResampledData, DstBufferSize
572 DirectParams *parms = &voice->Chan[chan].Direct;
573 const ALfloat *samples;
575 samples = DoFilters(
576 &parms->LowPass, &parms->HighPass, Device->FilteredData,
577 ResampledData, DstBufferSize, parms->FilterType
579 if(!voice->IsHrtf)
581 if(!Counter)
582 memcpy(parms->Gains.Current, parms->Gains.Target,
583 sizeof(parms->Gains.Current));
584 MixSamples(samples, voice->DirectOut.Channels, voice->DirectOut.Buffer,
585 parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
588 else
590 MixHrtfParams hrtfparams;
591 int lidx, ridx;
593 if(!Counter)
595 parms->Hrtf.Current = parms->Hrtf.Target;
596 for(j = 0;j < HRIR_LENGTH;j++)
598 hrtfparams.Steps.Coeffs[j][0] = 0.0f;
599 hrtfparams.Steps.Coeffs[j][1] = 0.0f;
601 hrtfparams.Steps.Delay[0] = 0;
602 hrtfparams.Steps.Delay[1] = 0;
604 else
606 ALfloat delta = 1.0f / (ALfloat)Counter;
607 ALfloat coeffdiff;
608 ALint delaydiff;
609 for(j = 0;j < IrSize;j++)
611 coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0];
612 hrtfparams.Steps.Coeffs[j][0] = coeffdiff * delta;
613 coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1];
614 hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta;
616 delaydiff = parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0];
617 hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta);
618 delaydiff = parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1];
619 hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta);
621 hrtfparams.Target = &parms->Hrtf.Target;
622 hrtfparams.Current = &parms->Hrtf.Current;
624 lidx = GetChannelIdxByName(Device->RealOut, FrontLeft);
625 ridx = GetChannelIdxByName(Device->RealOut, FrontRight);
626 assert(lidx != -1 && ridx != -1);
628 MixHrtfSamples(
629 voice->DirectOut.Buffer[lidx], voice->DirectOut.Buffer[ridx],
630 samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams,
631 &parms->Hrtf.State, DstBufferSize
636 for(send = 0;send < Device->NumAuxSends;send++)
638 SendParams *parms = &voice->Chan[chan].Send[send];
639 const ALfloat *samples;
641 if(!voice->SendOut[send].Buffer)
642 continue;
644 samples = DoFilters(
645 &parms->LowPass, &parms->HighPass, Device->FilteredData,
646 ResampledData, DstBufferSize, parms->FilterType
649 if(!Counter)
650 memcpy(parms->Gains.Current, parms->Gains.Target,
651 sizeof(parms->Gains.Current));
652 MixSamples(samples, voice->SendOut[send].Channels, voice->SendOut[send].Buffer,
653 parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
657 /* Update positions */
658 DataPosFrac += increment*DstBufferSize;
659 DataPosInt += DataPosFrac>>FRACTIONBITS;
660 DataPosFrac &= FRACTIONMASK;
662 OutPos += DstBufferSize;
663 voice->Offset += DstBufferSize;
664 Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
666 /* Handle looping sources */
667 while(1)
669 const ALbuffer *ALBuffer;
670 ALsizei DataSize = 0;
671 ALsizei LoopStart = 0;
672 ALsizei LoopEnd = 0;
674 if((ALBuffer=BufferListItem->buffer) != NULL)
676 DataSize = ALBuffer->SampleLen;
677 LoopStart = ALBuffer->LoopStart;
678 LoopEnd = ALBuffer->LoopEnd;
679 if((ALuint)LoopEnd > DataPosInt)
680 break;
683 if(Looping && Source->SourceType == AL_STATIC)
685 assert(LoopEnd > LoopStart);
686 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
687 break;
690 if((ALuint)DataSize > DataPosInt)
691 break;
693 if(!(BufferListItem=BufferListItem->next))
695 if(Looping)
696 BufferListItem = ATOMIC_LOAD(&Source->queue, almemory_order_acquire);
697 else
699 State = AL_STOPPED;
700 BufferListItem = NULL;
701 DataPosInt = 0;
702 DataPosFrac = 0;
703 break;
707 DataPosInt -= DataSize;
709 } while(State == AL_PLAYING && OutPos < SamplesToDo);
711 voice->Moving = AL_TRUE;
713 /* Update source info */
714 ATOMIC_STORE(&Source->state, State, almemory_order_relaxed);
715 ATOMIC_STORE(&Source->current_buffer, BufferListItem, almemory_order_relaxed);
716 ATOMIC_STORE(&Source->position, DataPosInt, almemory_order_relaxed);
717 ATOMIC_STORE(&Source->position_fraction, DataPosFrac, almemory_order_release);