Add a higher quality bsinc resampler using 24 sample points
[openal-soft.git] / Alc / mixer.c
blobc77488bc463281e3aed3b1576ca7153d05278161
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;
56 HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C;
58 MixerFunc SelectMixer(void)
60 #ifdef HAVE_NEON
61 if((CPUCapFlags&CPU_CAP_NEON))
62 return Mix_Neon;
63 #endif
64 #ifdef HAVE_SSE
65 if((CPUCapFlags&CPU_CAP_SSE))
66 return Mix_SSE;
67 #endif
68 return Mix_C;
71 RowMixerFunc SelectRowMixer(void)
73 #ifdef HAVE_NEON
74 if((CPUCapFlags&CPU_CAP_NEON))
75 return MixRow_Neon;
76 #endif
77 #ifdef HAVE_SSE
78 if((CPUCapFlags&CPU_CAP_SSE))
79 return MixRow_SSE;
80 #endif
81 return MixRow_C;
84 static inline HrtfMixerFunc SelectHrtfMixer(void)
86 #ifdef HAVE_NEON
87 if((CPUCapFlags&CPU_CAP_NEON))
88 return MixHrtf_Neon;
89 #endif
90 #ifdef HAVE_SSE
91 if((CPUCapFlags&CPU_CAP_SSE))
92 return MixHrtf_SSE;
93 #endif
94 return MixHrtf_C;
97 static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void)
99 #ifdef HAVE_NEON
100 if((CPUCapFlags&CPU_CAP_NEON))
101 return MixHrtfBlend_Neon;
102 #endif
103 #ifdef HAVE_SSE
104 if((CPUCapFlags&CPU_CAP_SSE))
105 return MixHrtfBlend_SSE;
106 #endif
107 return MixHrtfBlend_C;
110 ResamplerFunc SelectResampler(enum Resampler resampler)
112 switch(resampler)
114 case PointResampler:
115 return Resample_point_C;
116 case LinearResampler:
117 #ifdef HAVE_NEON
118 if((CPUCapFlags&CPU_CAP_NEON))
119 return Resample_lerp_Neon;
120 #endif
121 #ifdef HAVE_SSE4_1
122 if((CPUCapFlags&CPU_CAP_SSE4_1))
123 return Resample_lerp_SSE41;
124 #endif
125 #ifdef HAVE_SSE2
126 if((CPUCapFlags&CPU_CAP_SSE2))
127 return Resample_lerp_SSE2;
128 #endif
129 return Resample_lerp_C;
130 case FIR4Resampler:
131 #ifdef HAVE_NEON
132 if((CPUCapFlags&CPU_CAP_NEON))
133 return Resample_fir4_Neon;
134 #endif
135 #ifdef HAVE_SSE4_1
136 if((CPUCapFlags&CPU_CAP_SSE4_1))
137 return Resample_fir4_SSE41;
138 #endif
139 #ifdef HAVE_SSE3
140 if((CPUCapFlags&CPU_CAP_SSE3))
141 return Resample_fir4_SSE3;
142 #endif
143 return Resample_fir4_C;
144 case BSinc12Resampler:
145 case BSinc24Resampler:
146 #ifdef HAVE_NEON
147 if((CPUCapFlags&CPU_CAP_NEON))
148 return Resample_bsinc_Neon;
149 #endif
150 #ifdef HAVE_SSE
151 if((CPUCapFlags&CPU_CAP_SSE))
152 return Resample_bsinc_SSE;
153 #endif
154 return Resample_bsinc_C;
157 return Resample_point_C;
161 void aluInitMixer(void)
163 const char *str;
165 if(ConfigValueStr(NULL, NULL, "resampler", &str))
167 if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
168 ResamplerDefault = PointResampler;
169 else if(strcasecmp(str, "linear") == 0)
170 ResamplerDefault = LinearResampler;
171 else if(strcasecmp(str, "sinc4") == 0)
172 ResamplerDefault = FIR4Resampler;
173 else if(strcasecmp(str, "bsinc12") == 0)
174 ResamplerDefault = BSinc12Resampler;
175 else if(strcasecmp(str, "bsinc24") == 0)
176 ResamplerDefault = BSinc24Resampler;
177 else if(strcasecmp(str, "bsinc") == 0)
179 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str);
180 ResamplerDefault = BSinc12Resampler;
182 else if(strcasecmp(str, "cubic") == 0 || strcasecmp(str, "sinc8") == 0)
184 WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str);
185 ResamplerDefault = FIR4Resampler;
187 else
189 char *end;
190 long n = strtol(str, &end, 0);
191 if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
192 ResamplerDefault = n;
193 else
194 WARN("Invalid resampler: %s\n", str);
198 MixHrtfBlendSamples = SelectHrtfBlendMixer();
199 MixHrtfSamples = SelectHrtfMixer();
200 MixSamples = SelectMixer();
204 static inline ALfloat Sample_ALbyte(ALbyte val)
205 { return val * (1.0f/128.0f); }
207 static inline ALfloat Sample_ALshort(ALshort val)
208 { return val * (1.0f/32768.0f); }
210 static inline ALfloat Sample_ALfloat(ALfloat val)
211 { return val; }
213 #define DECL_TEMPLATE(T) \
214 static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \
215 ALint srcstep, ALsizei samples) \
217 ALsizei i; \
218 for(i = 0;i < samples;i++) \
219 dst[i] = Sample_##T(src[i*srcstep]); \
222 DECL_TEMPLATE(ALbyte)
223 DECL_TEMPLATE(ALshort)
224 DECL_TEMPLATE(ALfloat)
226 #undef DECL_TEMPLATE
228 static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep,
229 enum FmtType srctype, ALsizei samples)
231 switch(srctype)
233 case FmtByte:
234 Load_ALbyte(dst, src, srcstep, samples);
235 break;
236 case FmtShort:
237 Load_ALshort(dst, src, srcstep, samples);
238 break;
239 case FmtFloat:
240 Load_ALfloat(dst, src, srcstep, samples);
241 break;
245 static inline void SilenceSamples(ALfloat *dst, ALsizei samples)
247 ALsizei i;
248 for(i = 0;i < samples;i++)
249 dst[i] = 0.0f;
253 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
254 ALfloat *restrict dst, const ALfloat *restrict src,
255 ALsizei numsamples, enum ActiveFilters type)
257 ALsizei i;
258 switch(type)
260 case AF_None:
261 ALfilterState_processPassthru(lpfilter, src, numsamples);
262 ALfilterState_processPassthru(hpfilter, src, numsamples);
263 break;
265 case AF_LowPass:
266 ALfilterState_process(lpfilter, dst, src, numsamples);
267 ALfilterState_processPassthru(hpfilter, dst, numsamples);
268 return dst;
269 case AF_HighPass:
270 ALfilterState_processPassthru(lpfilter, src, numsamples);
271 ALfilterState_process(hpfilter, dst, src, numsamples);
272 return dst;
274 case AF_BandPass:
275 for(i = 0;i < numsamples;)
277 ALfloat temp[256];
278 ALsizei todo = mini(256, numsamples-i);
280 ALfilterState_process(lpfilter, temp, src+i, todo);
281 ALfilterState_process(hpfilter, dst+i, temp, todo);
282 i += todo;
284 return dst;
286 return src;
290 ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei SamplesToDo)
292 ALbufferlistitem *BufferListItem;
293 ALbufferlistitem *BufferLoopItem;
294 ALsizei NumChannels, SampleSize;
295 ResamplerFunc Resample;
296 ALsizei DataPosInt;
297 ALsizei DataPosFrac;
298 ALint64 DataSize64;
299 ALint increment;
300 ALsizei Counter;
301 ALsizei OutPos;
302 ALsizei IrSize;
303 bool isplaying;
304 bool firstpass;
305 bool isstatic;
306 ALsizei chan;
307 ALsizei send;
309 /* Get source info */
310 isplaying = true; /* Will only be called while playing. */
311 isstatic = Source->SourceType == AL_STATIC;
312 DataPosInt = ATOMIC_LOAD(&voice->position, almemory_order_acquire);
313 DataPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
314 BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
315 BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed);
316 NumChannels = voice->NumChannels;
317 SampleSize = voice->SampleSize;
318 increment = voice->Step;
320 IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0);
322 Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
323 Resample_copy_C : voice->Resampler);
325 Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0;
326 firstpass = true;
327 OutPos = 0;
329 do {
330 ALsizei SrcBufferSize, DstBufferSize;
332 /* Figure out how many buffer samples will be needed */
333 DataSize64 = SamplesToDo-OutPos;
334 DataSize64 *= increment;
335 DataSize64 += DataPosFrac+FRACTIONMASK;
336 DataSize64 >>= FRACTIONBITS;
337 DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
339 SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
341 /* Figure out how many samples we can actually mix from this. */
342 DataSize64 = SrcBufferSize;
343 DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
344 DataSize64 <<= FRACTIONBITS;
345 DataSize64 -= DataPosFrac;
347 DstBufferSize = (ALsizei)((DataSize64+(increment-1)) / increment);
348 DstBufferSize = mini(DstBufferSize, (SamplesToDo-OutPos));
350 /* Some mixers like having a multiple of 4, so try to give that unless
351 * this is the last update. */
352 if(OutPos+DstBufferSize < SamplesToDo)
353 DstBufferSize &= ~3;
355 for(chan = 0;chan < NumChannels;chan++)
357 const ALfloat *ResampledData;
358 ALfloat *SrcData = Device->SourceData;
359 ALsizei SrcDataSize;
361 /* Load the previous samples into the source data first. */
362 memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
363 SrcDataSize = MAX_PRE_SAMPLES;
365 if(isstatic)
367 const ALbuffer *ALBuffer = BufferListItem->buffer;
368 const ALubyte *Data = ALBuffer->data;
369 ALsizei DataSize;
371 /* Offset buffer data to current channel */
372 Data += chan*SampleSize;
374 /* If current pos is beyond the loop range, do not loop */
375 if(!BufferLoopItem || DataPosInt >= ALBuffer->LoopEnd)
377 BufferLoopItem = NULL;
379 /* Load what's left to play from the source buffer, and
380 * clear the rest of the temp buffer */
381 DataSize = minu(SrcBufferSize - SrcDataSize,
382 ALBuffer->SampleLen - DataPosInt);
384 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
385 NumChannels, ALBuffer->FmtType, DataSize);
386 SrcDataSize += DataSize;
388 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
389 SrcDataSize += SrcBufferSize - SrcDataSize;
391 else
393 ALsizei LoopStart = ALBuffer->LoopStart;
394 ALsizei LoopEnd = ALBuffer->LoopEnd;
396 /* Load what's left of this loop iteration, then load
397 * repeats of the loop section */
398 DataSize = minu(SrcBufferSize - SrcDataSize, LoopEnd - DataPosInt);
400 LoadSamples(&SrcData[SrcDataSize], &Data[DataPosInt * NumChannels*SampleSize],
401 NumChannels, ALBuffer->FmtType, DataSize);
402 SrcDataSize += DataSize;
404 DataSize = LoopEnd-LoopStart;
405 while(SrcBufferSize > SrcDataSize)
407 DataSize = mini(SrcBufferSize - SrcDataSize, DataSize);
409 LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
410 NumChannels, ALBuffer->FmtType, DataSize);
411 SrcDataSize += DataSize;
415 else
417 /* Crawl the buffer queue to fill in the temp buffer */
418 ALbufferlistitem *tmpiter = BufferListItem;
419 ALsizei pos = DataPosInt;
421 while(tmpiter && SrcBufferSize > SrcDataSize)
423 const ALbuffer *ALBuffer;
424 if((ALBuffer=tmpiter->buffer) != NULL)
426 const ALubyte *Data = ALBuffer->data;
427 ALsizei DataSize = ALBuffer->SampleLen;
429 /* Skip the data already played */
430 if(DataSize <= pos)
431 pos -= DataSize;
432 else
434 Data += (pos*NumChannels + chan)*SampleSize;
435 DataSize -= pos;
436 pos -= pos;
438 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
439 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
440 ALBuffer->FmtType, DataSize);
441 SrcDataSize += DataSize;
444 tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire);
445 if(!tmpiter && BufferLoopItem)
446 tmpiter = BufferLoopItem;
447 else if(!tmpiter)
449 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
450 SrcDataSize += SrcBufferSize - SrcDataSize;
455 /* Store the last source samples used for next time. */
456 memcpy(voice->PrevSamples[chan],
457 &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
458 MAX_PRE_SAMPLES*sizeof(ALfloat)
461 /* Now resample, then filter and mix to the appropriate outputs. */
462 ResampledData = Resample(&voice->ResampleState,
463 &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
464 Device->ResampledData, DstBufferSize
467 DirectParams *parms = &voice->Direct.Params[chan];
468 const ALfloat *samples;
470 samples = DoFilters(
471 &parms->LowPass, &parms->HighPass, Device->FilteredData,
472 ResampledData, DstBufferSize, voice->Direct.FilterType
474 if(!(voice->Flags&VOICE_HAS_HRTF))
476 if(!Counter)
477 memcpy(parms->Gains.Current, parms->Gains.Target,
478 sizeof(parms->Gains.Current));
479 if(!(voice->Flags&VOICE_HAS_NFC))
480 MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
481 parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
482 DstBufferSize
484 else
486 ALfloat *nfcsamples = Device->NFCtrlData;
487 ALsizei chanoffset = 0;
489 MixSamples(samples,
490 voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
491 parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
492 DstBufferSize
494 chanoffset += voice->Direct.ChannelsPerOrder[0];
495 #define APPLY_NFC_MIX(order) \
496 if(voice->Direct.ChannelsPerOrder[order] > 0) \
498 NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \
499 samples, DstBufferSize); \
500 MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \
501 voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
502 parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \
503 ); \
504 chanoffset += voice->Direct.ChannelsPerOrder[order]; \
506 APPLY_NFC_MIX(1)
507 APPLY_NFC_MIX(2)
508 APPLY_NFC_MIX(3)
509 #undef APPLY_NFC_MIX
512 else
514 MixHrtfParams hrtfparams;
515 ALsizei fademix = 0;
516 int lidx, ridx;
518 lidx = GetChannelIdxByName(Device->RealOut, FrontLeft);
519 ridx = GetChannelIdxByName(Device->RealOut, FrontRight);
520 assert(lidx != -1 && ridx != -1);
522 if(!Counter)
524 /* No fading, just overwrite the old HRTF params. */
525 parms->Hrtf.Old = parms->Hrtf.Target;
527 else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
529 /* The old HRTF params are silent, so overwrite the old
530 * coefficients with the new, and reset the old gain to
531 * 0. The future mix will then fade from silence.
533 parms->Hrtf.Old = parms->Hrtf.Target;
534 parms->Hrtf.Old.Gain = 0.0f;
536 else if(firstpass)
538 ALfloat gain;
540 /* Fade between the coefficients over 128 samples. */
541 fademix = mini(DstBufferSize, 128);
543 /* The new coefficients need to fade in completely
544 * since they're replacing the old ones. To keep the
545 * gain fading consistent, interpolate between the old
546 * and new target gains given how much of the fade time
547 * this mix handles.
549 gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain,
550 minf(1.0f, (ALfloat)fademix/Counter));
551 hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
552 hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
553 hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
554 hrtfparams.Gain = 0.0f;
555 hrtfparams.GainStep = gain / (ALfloat)fademix;
557 MixHrtfBlendSamples(
558 voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
559 samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old,
560 &hrtfparams, &parms->Hrtf.State, fademix
562 /* Update the old parameters with the result. */
563 parms->Hrtf.Old = parms->Hrtf.Target;
564 if(fademix < Counter)
565 parms->Hrtf.Old.Gain = hrtfparams.Gain;
568 if(fademix < DstBufferSize)
570 ALsizei todo = DstBufferSize - fademix;
571 ALfloat gain = parms->Hrtf.Target.Gain;
573 /* Interpolate the target gain if the gain fading lasts
574 * longer than this mix.
576 if(Counter > DstBufferSize)
577 gain = lerp(parms->Hrtf.Old.Gain, gain,
578 (ALfloat)todo/(Counter-fademix));
580 hrtfparams.Coeffs = SAFE_CONST(ALfloat2*,parms->Hrtf.Target.Coeffs);
581 hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
582 hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
583 hrtfparams.Gain = parms->Hrtf.Old.Gain;
584 hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo;
585 MixHrtfSamples(
586 voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
587 samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize,
588 &hrtfparams, &parms->Hrtf.State, todo
590 /* Store the interpolated gain or the final target gain
591 * depending if the fade is done.
593 if(DstBufferSize < Counter)
594 parms->Hrtf.Old.Gain = gain;
595 else
596 parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain;
601 for(send = 0;send < Device->NumAuxSends;send++)
603 SendParams *parms = &voice->Send[send].Params[chan];
604 const ALfloat *samples;
606 if(!voice->Send[send].Buffer)
607 continue;
609 samples = DoFilters(
610 &parms->LowPass, &parms->HighPass, Device->FilteredData,
611 ResampledData, DstBufferSize, voice->Send[send].FilterType
614 if(!Counter)
615 memcpy(parms->Gains.Current, parms->Gains.Target,
616 sizeof(parms->Gains.Current));
617 MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer,
618 parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
622 /* Update positions */
623 DataPosFrac += increment*DstBufferSize;
624 DataPosInt += DataPosFrac>>FRACTIONBITS;
625 DataPosFrac &= FRACTIONMASK;
627 OutPos += DstBufferSize;
628 voice->Offset += DstBufferSize;
629 Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
630 firstpass = false;
632 /* Handle looping sources */
633 while(1)
635 const ALbuffer *ALBuffer;
636 ALsizei DataSize = 0;
637 ALsizei LoopStart = 0;
638 ALsizei LoopEnd = 0;
640 if((ALBuffer=BufferListItem->buffer) != NULL)
642 DataSize = ALBuffer->SampleLen;
643 LoopStart = ALBuffer->LoopStart;
644 LoopEnd = ALBuffer->LoopEnd;
645 if(LoopEnd > DataPosInt)
646 break;
649 if(isstatic && BufferLoopItem)
651 assert(LoopEnd > LoopStart);
652 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
653 break;
656 if(DataSize > DataPosInt)
657 break;
659 BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire);
660 if(!BufferListItem)
662 BufferListItem = BufferLoopItem;
663 if(!BufferListItem)
665 isplaying = false;
666 DataPosInt = 0;
667 DataPosFrac = 0;
668 break;
672 DataPosInt -= DataSize;
674 } while(isplaying && OutPos < SamplesToDo);
676 voice->Flags |= VOICE_IS_FADING;
678 /* Update source info */
679 ATOMIC_STORE(&voice->position, DataPosInt, almemory_order_relaxed);
680 ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed);
681 ATOMIC_STORE(&voice->current_buffer, BufferListItem, almemory_order_release);
682 return isplaying;