Rename VOICE_IS_HRTF to VOICE_HAS_HRTF
[openal-soft.git] / Alc / mixer.c
blobb632d6cadb038cb0cd4fdd0abe1503d84925eeb1
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(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size);
47 /* BSinc requires up to 11 extra samples before the current position, and 12 after. */
48 static_assert(MAX_PRE_SAMPLES >= 11, "MAX_PRE_SAMPLES must be at least 11!");
49 static_assert(MAX_POST_SAMPLES >= 12, "MAX_POST_SAMPLES must be at least 12!");
52 enum Resampler ResamplerDefault = LinearResampler;
54 static MixerFunc MixSamples = Mix_C;
55 static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
57 MixerFunc SelectMixer(void)
59 #ifdef HAVE_NEON
60 if((CPUCapFlags&CPU_CAP_NEON))
61 return Mix_Neon;
62 #endif
63 #ifdef HAVE_SSE
64 if((CPUCapFlags&CPU_CAP_SSE))
65 return Mix_SSE;
66 #endif
67 return Mix_C;
70 RowMixerFunc SelectRowMixer(void)
72 #ifdef HAVE_NEON
73 if((CPUCapFlags&CPU_CAP_NEON))
74 return MixRow_Neon;
75 #endif
76 #ifdef HAVE_SSE
77 if((CPUCapFlags&CPU_CAP_SSE))
78 return MixRow_SSE;
79 #endif
80 return MixRow_C;
83 static inline HrtfMixerFunc SelectHrtfMixer(void)
85 #ifdef HAVE_NEON
86 if((CPUCapFlags&CPU_CAP_NEON))
87 return MixHrtf_Neon;
88 #endif
89 #ifdef HAVE_SSE
90 if((CPUCapFlags&CPU_CAP_SSE))
91 return MixHrtf_SSE;
92 #endif
94 return MixHrtf_C;
97 ResamplerFunc SelectResampler(enum Resampler resampler)
99 switch(resampler)
101 case PointResampler:
102 return Resample_point32_C;
103 case LinearResampler:
104 #ifdef HAVE_NEON
105 if((CPUCapFlags&CPU_CAP_NEON))
106 return Resample_lerp32_Neon;
107 #endif
108 #ifdef HAVE_SSE4_1
109 if((CPUCapFlags&CPU_CAP_SSE4_1))
110 return Resample_lerp32_SSE41;
111 #endif
112 #ifdef HAVE_SSE2
113 if((CPUCapFlags&CPU_CAP_SSE2))
114 return Resample_lerp32_SSE2;
115 #endif
116 return Resample_lerp32_C;
117 case FIR4Resampler:
118 #ifdef HAVE_NEON
119 if((CPUCapFlags&CPU_CAP_NEON))
120 return Resample_fir4_32_Neon;
121 #endif
122 #ifdef HAVE_SSE4_1
123 if((CPUCapFlags&CPU_CAP_SSE4_1))
124 return Resample_fir4_32_SSE41;
125 #endif
126 #ifdef HAVE_SSE3
127 if((CPUCapFlags&CPU_CAP_SSE3))
128 return Resample_fir4_32_SSE3;
129 #endif
130 return Resample_fir4_32_C;
131 case BSincResampler:
132 #ifdef HAVE_NEON
133 if((CPUCapFlags&CPU_CAP_NEON))
134 return Resample_bsinc32_Neon;
135 #endif
136 #ifdef HAVE_SSE
137 if((CPUCapFlags&CPU_CAP_SSE))
138 return Resample_bsinc32_SSE;
139 #endif
140 return Resample_bsinc32_C;
143 return Resample_point32_C;
147 void aluInitMixer(void)
149 const char *str;
151 if(ConfigValueStr(NULL, NULL, "resampler", &str))
153 if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
154 ResamplerDefault = PointResampler;
155 else if(strcasecmp(str, "linear") == 0)
156 ResamplerDefault = LinearResampler;
157 else if(strcasecmp(str, "sinc4") == 0)
158 ResamplerDefault = FIR4Resampler;
159 else if(strcasecmp(str, "bsinc") == 0)
160 ResamplerDefault = BSincResampler;
161 else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 0)
163 WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str);
164 ResamplerDefault = FIR4Resampler;
166 else
168 char *end;
169 long n = strtol(str, &end, 0);
170 if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
171 ResamplerDefault = n;
172 else
173 WARN("Invalid resampler: %s\n", str);
177 MixHrtfSamples = SelectHrtfMixer();
178 MixSamples = SelectMixer();
182 static inline ALfloat Sample_ALbyte(ALbyte val)
183 { return val * (1.0f/128.0f); }
185 static inline ALfloat Sample_ALshort(ALshort val)
186 { return val * (1.0f/32768.0f); }
188 static inline ALfloat Sample_ALfloat(ALfloat val)
189 { return val; }
191 #define DECL_TEMPLATE(T) \
192 static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\
194 ALsizei i; \
195 for(i = 0;i < samples;i++) \
196 dst[i] = Sample_##T(src[i*srcstep]); \
199 DECL_TEMPLATE(ALbyte)
200 DECL_TEMPLATE(ALshort)
201 DECL_TEMPLATE(ALfloat)
203 #undef DECL_TEMPLATE
205 static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum FmtType srctype, ALsizei samples)
207 switch(srctype)
209 case FmtByte:
210 Load_ALbyte(dst, src, srcstep, samples);
211 break;
212 case FmtShort:
213 Load_ALshort(dst, src, srcstep, samples);
214 break;
215 case FmtFloat:
216 Load_ALfloat(dst, src, srcstep, samples);
217 break;
221 static inline void SilenceSamples(ALfloat *dst, ALsizei samples)
223 ALsizei i;
224 for(i = 0;i < samples;i++)
225 dst[i] = 0.0f;
229 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
230 ALfloat *restrict dst, const ALfloat *restrict src,
231 ALsizei numsamples, enum ActiveFilters type)
233 ALsizei i;
234 switch(type)
236 case AF_None:
237 ALfilterState_processPassthru(lpfilter, src, numsamples);
238 ALfilterState_processPassthru(hpfilter, src, numsamples);
239 break;
241 case AF_LowPass:
242 ALfilterState_process(lpfilter, dst, src, numsamples);
243 ALfilterState_processPassthru(hpfilter, dst, numsamples);
244 return dst;
245 case AF_HighPass:
246 ALfilterState_processPassthru(lpfilter, src, numsamples);
247 ALfilterState_process(hpfilter, dst, src, numsamples);
248 return dst;
250 case AF_BandPass:
251 for(i = 0;i < numsamples;)
253 ALfloat temp[256];
254 ALsizei todo = mini(256, numsamples-i);
256 ALfilterState_process(lpfilter, temp, src+i, todo);
257 ALfilterState_process(hpfilter, dst+i, temp, todo);
258 i += todo;
260 return dst;
262 return src;
266 ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo)
268 ALbufferlistitem *BufferListItem;
269 ALbufferlistitem *BufferLoopItem;
270 ALsizei NumChannels, SampleSize;
271 ResamplerFunc Resample;
272 ALsizei DataPosInt;
273 ALsizei DataPosFrac;
274 ALint64 DataSize64;
275 ALint increment;
276 ALsizei Counter;
277 ALsizei OutPos;
278 ALsizei IrSize;
279 bool isplaying;
280 bool firstpass;
281 ALsizei chan;
282 ALsizei send;
284 /* Get source info */
285 isplaying = true; /* Will only be called while playing. */
286 DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire);
287 DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
288 BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
289 BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed);
290 NumChannels = voice->NumChannels;
291 SampleSize = voice->SampleSize;
292 increment = voice->Step;
294 IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0);
296 Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
297 Resample_copy32_C : voice->Resampler);
299 Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0;
300 firstpass = true;
301 OutPos = 0;
303 do {
304 ALsizei SrcBufferSize, DstBufferSize;
306 /* Figure out how many buffer samples will be needed */
307 DataSize64 = SamplesToDo-OutPos;
308 DataSize64 *= increment;
309 DataSize64 += DataPosFrac+FRACTIONMASK;
310 DataSize64 >>= FRACTIONBITS;
311 DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
313 SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
315 /* Figure out how many samples we can actually mix from this. */
316 DataSize64 = SrcBufferSize;
317 DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
318 DataSize64 <<= FRACTIONBITS;
319 DataSize64 -= DataPosFrac;
321 DstBufferSize = (ALsizei)((DataSize64+(increment-1)) / increment);
322 DstBufferSize = mini(DstBufferSize, (SamplesToDo-OutPos));
324 /* Some mixers like having a multiple of 4, so try to give that unless
325 * this is the last update. */
326 if(OutPos+DstBufferSize < SamplesToDo)
327 DstBufferSize &= ~3;
329 for(chan = 0;chan < NumChannels;chan++)
331 const ALfloat *ResampledData;
332 ALfloat *SrcData = Device->SourceData;
333 ALsizei SrcDataSize;
335 /* Load the previous samples into the source data first. */
336 memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
337 SrcDataSize = MAX_PRE_SAMPLES;
339 if(Source->SourceType == AL_STATIC)
341 const ALbuffer *ALBuffer = BufferListItem->buffer;
342 const ALubyte *Data = ALBuffer->data;
343 ALsizei DataSize;
345 /* Offset buffer data to current channel */
346 Data += chan*SampleSize;
348 /* If current pos is beyond the loop range, do not loop */
349 if(!BufferLoopItem || DataPosInt >= ALBuffer->LoopEnd)
351 BufferLoopItem = NULL;
353 /* Load what's left to play from the source buffer, and
354 * clear the rest of the temp buffer */
355 DataSize = minu(SrcBufferSize - SrcDataSize,
356 ALBuffer->SampleLen - DataPosInt);
358 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
359 NumChannels, ALBuffer->FmtType, DataSize);
360 SrcDataSize += DataSize;
362 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
363 SrcDataSize += SrcBufferSize - SrcDataSize;
365 else
367 ALsizei LoopStart = ALBuffer->LoopStart;
368 ALsizei LoopEnd = ALBuffer->LoopEnd;
370 /* Load what's left of this loop iteration, then load
371 * repeats of the loop section */
372 DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt);
374 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
375 NumChannels, ALBuffer->FmtType, DataSize);
376 SrcDataSize += DataSize;
378 DataSize = LoopEnd-LoopStart;
379 while(SrcBufferSize > SrcDataSize)
381 DataSize = mini(SrcBufferSize - SrcDataSize, DataSize);
383 LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
384 NumChannels, ALBuffer->FmtType, DataSize);
385 SrcDataSize += DataSize;
389 else
391 /* Crawl the buffer queue to fill in the temp buffer */
392 ALbufferlistitem *tmpiter = BufferListItem;
393 ALsizei pos = DataPosInt;
395 while(tmpiter && SrcBufferSize > SrcDataSize)
397 const ALbuffer *ALBuffer;
398 if((ALBuffer=tmpiter->buffer) != NULL)
400 const ALubyte *Data = ALBuffer->data;
401 ALsizei DataSize = ALBuffer->SampleLen;
403 /* Skip the data already played */
404 if(DataSize <= pos)
405 pos -= DataSize;
406 else
408 Data += (pos*NumChannels + chan)*SampleSize;
409 DataSize -= pos;
410 pos -= pos;
412 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
413 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
414 ALBuffer->FmtType, DataSize);
415 SrcDataSize += DataSize;
418 tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire);
419 if(!tmpiter && BufferLoopItem)
420 tmpiter = BufferLoopItem;
421 else if(!tmpiter)
423 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
424 SrcDataSize += SrcBufferSize - SrcDataSize;
429 /* Store the last source samples used for next time. */
430 memcpy(voice->PrevSamples[chan],
431 &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
432 MAX_PRE_SAMPLES*sizeof(ALfloat)
435 /* Now resample, then filter and mix to the appropriate outputs. */
436 ResampledData = Resample(&voice->ResampleState,
437 &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
438 Device->ResampledData, DstBufferSize
441 DirectParams *parms = &voice->Direct.Params[chan];
442 const ALfloat *samples;
444 samples = DoFilters(
445 &parms->LowPass, &parms->HighPass, Device->FilteredData,
446 ResampledData, DstBufferSize, parms->FilterType
448 if(!(voice->Flags&VOICE_HAS_HRTF))
450 if(!Counter)
451 memcpy(parms->Gains.Current, parms->Gains.Target,
452 sizeof(parms->Gains.Current));
453 if(!(voice->Flags&VOICE_HAS_NFC))
454 MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
455 parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
456 DstBufferSize
458 else
460 static void (*const NfcUpdate[MAX_AMBI_ORDER])(
461 NfcFilter*,float*,const float*,const int
462 ) = {
463 NfcFilterUpdate1, NfcFilterUpdate2, NfcFilterUpdate3
465 ALfloat *nfcsamples = Device->NFCtrlData;
466 ALsizei ord, chanoffset = 0;
468 MixSamples(samples,
469 voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
470 parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
471 DstBufferSize
473 chanoffset += voice->Direct.ChannelsPerOrder[0];
474 for(ord = 1;ord < MAX_AMBI_ORDER+1;ord++)
476 if(voice->Direct.ChannelsPerOrder[ord] <= 0)
477 break;
478 NfcUpdate[ord-1](&parms->NFCtrlFilter[ord-1], nfcsamples, samples,
479 DstBufferSize);
480 MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[ord],
481 voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset,
482 parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize
484 chanoffset += voice->Direct.ChannelsPerOrder[ord];
488 else
490 MixHrtfParams hrtfparams;
491 ALsizei fademix = 0;
492 int lidx, ridx;
494 lidx = GetChannelIdxByName(Device->RealOut, FrontLeft);
495 ridx = GetChannelIdxByName(Device->RealOut, FrontRight);
496 assert(lidx != -1 && ridx != -1);
498 if(!Counter)
500 /* No fading, just overwrite the old HRTF params. */
501 parms->Hrtf.Old = parms->Hrtf.Target;
503 else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
505 /* The old HRTF params are silent, so overwrite the old
506 * coefficients with the new, and reset the old gain to
507 * 0. The future mix will then fade from silence.
509 parms->Hrtf.Old = parms->Hrtf.Target;
510 parms->Hrtf.Old.Gain = 0.0f;
512 else if(firstpass && parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD)
514 HrtfState backupstate = parms->Hrtf.State;
515 ALfloat gain;
517 /* Fade between the coefficients over 64 samples. */
518 fademix = mini(DstBufferSize, 64);
520 /* The old coefficients need to fade to silence
521 * completely since they'll be replaced after this mix.
523 hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Old.Coeffs);
524 hrtfparams.Delay[0] = parms->Hrtf.Old.Delay[0];
525 hrtfparams.Delay[1] = parms->Hrtf.Old.Delay[1];
526 hrtfparams.Gain = parms->Hrtf.Old.Gain;
527 hrtfparams.GainStep = -hrtfparams.Gain / (ALfloat)fademix;
528 MixHrtfSamples(
529 voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
530 samples, voice->Offset, OutPos, IrSize, &hrtfparams,
531 &backupstate, fademix
534 /* The new coefficients need to fade in completely
535 * since they're replacing the old ones. To keep the
536 * gain fading consistent, interpolate between the old
537 * and new target gains given how much of the fade time
538 * this mix handles.
540 gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain,
541 minf(1.0f, (ALfloat)fademix/Counter));
542 hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
543 hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
544 hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
545 hrtfparams.Gain = 0.0f;
546 hrtfparams.GainStep = gain / (ALfloat)fademix;
547 MixHrtfSamples(
548 voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
549 samples, voice->Offset, OutPos, IrSize, &hrtfparams,
550 &parms->Hrtf.State, fademix
552 /* Update the old parameters with the result. */
553 parms->Hrtf.Old = parms->Hrtf.Target;
554 if(fademix < Counter)
555 parms->Hrtf.Old.Gain = hrtfparams.Gain;
558 if(fademix < DstBufferSize)
560 ALsizei todo = DstBufferSize - fademix;
561 ALfloat gain = parms->Hrtf.Target.Gain;
563 /* Interpolate the target gain if the gain fading lasts
564 * longer than this mix.
566 if(Counter > DstBufferSize)
567 gain = lerp(parms->Hrtf.Old.Gain, gain,
568 (ALfloat)todo/(Counter-fademix));
570 hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
571 hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
572 hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
573 hrtfparams.Gain = parms->Hrtf.Old.Gain;
574 hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo;
575 MixHrtfSamples(
576 voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
577 samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize,
578 &hrtfparams, &parms->Hrtf.State, todo
580 /* Store the interpolated gain or the final target gain
581 * depending if the fade is done.
583 if(DstBufferSize < Counter)
584 parms->Hrtf.Old.Gain = gain;
585 else
586 parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain;
591 for(send = 0;send < Device->NumAuxSends;send++)
593 SendParams *parms = &voice->Send[send].Params[chan];
594 const ALfloat *samples;
596 if(!voice->Send[send].Buffer)
597 continue;
599 samples = DoFilters(
600 &parms->LowPass, &parms->HighPass, Device->FilteredData,
601 ResampledData, DstBufferSize, parms->FilterType
604 if(!Counter)
605 memcpy(parms->Gains.Current, parms->Gains.Target,
606 sizeof(parms->Gains.Current));
607 MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer,
608 parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
612 /* Update positions */
613 DataPosFrac += increment*DstBufferSize;
614 DataPosInt += DataPosFrac>>FRACTIONBITS;
615 DataPosFrac &= FRACTIONMASK;
617 OutPos += DstBufferSize;
618 voice->Offset += DstBufferSize;
619 Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
620 firstpass = false;
622 /* Handle looping sources */
623 while(1)
625 const ALbuffer *ALBuffer;
626 ALsizei DataSize = 0;
627 ALsizei LoopStart = 0;
628 ALsizei LoopEnd = 0;
630 if((ALBuffer=BufferListItem->buffer) != NULL)
632 DataSize = ALBuffer->SampleLen;
633 LoopStart = ALBuffer->LoopStart;
634 LoopEnd = ALBuffer->LoopEnd;
635 if(LoopEnd > DataPosInt)
636 break;
639 if(BufferLoopItem && Source->SourceType == AL_STATIC)
641 assert(LoopEnd > LoopStart);
642 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
643 break;
646 if(DataSize > DataPosInt)
647 break;
649 BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire);
650 if(!BufferListItem)
652 BufferListItem = BufferLoopItem;
653 if(!BufferListItem)
655 isplaying = false;
656 DataPosInt = 0;
657 DataPosFrac = 0;
658 break;
662 DataPosInt -= DataSize;
664 } while(isplaying && OutPos < SamplesToDo);
666 voice->Flags |= VOICE_IS_FADING;
668 /* Update source info */
669 ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed);
670 ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed);
671 ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release);
672 return isplaying;