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
34 #include "alListener.h"
35 #include "alAuxEffectSlot.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
;
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)
71 if((CPUCapFlags
&CPU_CAP_SSE
))
75 if((CPUCapFlags
&CPU_CAP_NEON
))
82 RowMixerFunc
SelectRowMixer(void)
85 if((CPUCapFlags
&CPU_CAP_SSE
))
89 if((CPUCapFlags
&CPU_CAP_NEON
))
95 static inline HrtfMixerFunc
SelectHrtfMixer(void)
98 if((CPUCapFlags
&CPU_CAP_SSE
))
102 if((CPUCapFlags
&CPU_CAP_NEON
))
109 static inline ResamplerFunc
SelectResampler(enum Resampler resampler
)
114 return Resample_point32_C
;
115 case LinearResampler
:
117 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
118 return Resample_lerp32_SSE41
;
121 if((CPUCapFlags
&CPU_CAP_SSE2
))
122 return Resample_lerp32_SSE2
;
124 return Resample_lerp32_C
;
127 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
128 return Resample_fir4_32_SSE41
;
131 if((CPUCapFlags
&CPU_CAP_SSE3
))
132 return Resample_fir4_32_SSE3
;
134 return Resample_fir4_32_C
;
137 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
138 return Resample_fir8_32_SSE41
;
141 if((CPUCapFlags
&CPU_CAP_SSE3
))
142 return Resample_fir8_32_SSE3
;
144 return Resample_fir8_32_C
;
147 if((CPUCapFlags
&CPU_CAP_SSE
))
148 return Resample_bsinc32_SSE
;
150 return Resample_bsinc32_C
;
153 return Resample_point32_C
;
157 /* The sinc resampler makes use of a Kaiser window to limit the needed sample
158 * points to 4 and 8, respectively.
162 #define M_PI (3.14159265358979323846)
164 static inline double Sinc(double x
)
166 if(x
== 0.0) return 1.0;
167 return sin(x
*M_PI
) / (x
*M_PI
);
170 /* The zero-order modified Bessel function of the first kind, used for the
173 * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
174 * = sum_{k=0}^inf ((x / 2)^k / k!)^2
176 static double BesselI_0(double x
)
178 double term
, sum
, x2
, y
, last_sum
;
181 /* Start at k=1 since k=0 is trivial. */
187 /* Let the integration converge until the term of the sum is no longer
196 } while(sum
!= last_sum
);
200 /* Calculate a Kaiser window from the given beta value and a normalized k
203 * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
206 * Where k can be calculated as:
208 * k = i / l, where -l <= i <= l.
212 * k = 2 i / M - 1, where 0 <= i <= M.
214 static inline double Kaiser(double b
, double k
)
216 if(k
<= -1.0 || k
>= 1.0) return 0.0;
217 return BesselI_0(b
* sqrt(1.0 - (k
*k
))) / BesselI_0(b
);
220 static inline double CalcKaiserBeta(double rejection
)
223 return 0.1102 * (rejection
- 8.7);
224 if(rejection
>= 21.0)
225 return (0.5842 * pow(rejection
- 21.0, 0.4)) +
226 (0.07886 * (rejection
- 21.0));
230 static float SincKaiser(double r
, double x
)
232 /* Limit rippling to -60dB. */
233 return (float)(Kaiser(CalcKaiserBeta(60.0), x
/ r
) * Sinc(x
));
237 void aluInitMixer(void)
239 enum Resampler resampler
= ResamplerDefault
;
243 if(ConfigValueStr(NULL
, NULL
, "resampler", &str
))
245 if(strcasecmp(str
, "point") == 0 || strcasecmp(str
, "none") == 0)
246 resampler
= PointResampler
;
247 else if(strcasecmp(str
, "linear") == 0)
248 resampler
= LinearResampler
;
249 else if(strcasecmp(str
, "sinc4") == 0)
250 resampler
= FIR4Resampler
;
251 else if(strcasecmp(str
, "sinc8") == 0)
252 resampler
= FIR8Resampler
;
253 else if(strcasecmp(str
, "bsinc") == 0)
254 resampler
= BSincResampler
;
255 else if(strcasecmp(str
, "cubic") == 0)
257 WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
258 resampler
= FIR4Resampler
;
263 long n
= strtol(str
, &end
, 0);
264 if(*end
== '\0' && (n
== PointResampler
|| n
== LinearResampler
|| n
== FIR4Resampler
))
267 WARN("Invalid resampler: %s\n", str
);
271 if(resampler
== FIR8Resampler
)
272 for(i
= 0;i
< FRACTIONONE
;i
++)
274 ALdouble mu
= (ALdouble
)i
/ FRACTIONONE
;
275 ResampleCoeffs
.FIR8
[i
][0] = SincKaiser(4.0, mu
- -3.0);
276 ResampleCoeffs
.FIR8
[i
][1] = SincKaiser(4.0, mu
- -2.0);
277 ResampleCoeffs
.FIR8
[i
][2] = SincKaiser(4.0, mu
- -1.0);
278 ResampleCoeffs
.FIR8
[i
][3] = SincKaiser(4.0, mu
- 0.0);
279 ResampleCoeffs
.FIR8
[i
][4] = SincKaiser(4.0, mu
- 1.0);
280 ResampleCoeffs
.FIR8
[i
][5] = SincKaiser(4.0, mu
- 2.0);
281 ResampleCoeffs
.FIR8
[i
][6] = SincKaiser(4.0, mu
- 3.0);
282 ResampleCoeffs
.FIR8
[i
][7] = SincKaiser(4.0, mu
- 4.0);
284 else if(resampler
== FIR4Resampler
)
285 for(i
= 0;i
< FRACTIONONE
;i
++)
287 ALdouble mu
= (ALdouble
)i
/ FRACTIONONE
;
288 ResampleCoeffs
.FIR4
[i
][0] = SincKaiser(2.0, mu
- -1.0);
289 ResampleCoeffs
.FIR4
[i
][1] = SincKaiser(2.0, mu
- 0.0);
290 ResampleCoeffs
.FIR4
[i
][2] = SincKaiser(2.0, mu
- 1.0);
291 ResampleCoeffs
.FIR4
[i
][3] = SincKaiser(2.0, mu
- 2.0);
294 MixHrtfSamples
= SelectHrtfMixer();
295 MixSamples
= SelectMixer();
296 ResampleSamples
= SelectResampler(resampler
);
300 static inline ALfloat
Sample_ALbyte(ALbyte val
)
301 { return val
* (1.0f
/127.0f
); }
303 static inline ALfloat
Sample_ALshort(ALshort val
)
304 { return val
* (1.0f
/32767.0f
); }
306 static inline ALfloat
Sample_ALfloat(ALfloat val
)
309 #define DECL_TEMPLATE(T) \
310 static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
313 for(i = 0;i < samples;i++) \
314 dst[i] = Sample_##T(src[i*srcstep]); \
317 DECL_TEMPLATE(ALbyte
)
318 DECL_TEMPLATE(ALshort
)
319 DECL_TEMPLATE(ALfloat
)
323 static void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALuint srcstep
, enum FmtType srctype
, ALuint samples
)
328 Load_ALbyte(dst
, src
, srcstep
, samples
);
331 Load_ALshort(dst
, src
, srcstep
, samples
);
334 Load_ALfloat(dst
, src
, srcstep
, samples
);
339 static inline void SilenceSamples(ALfloat
*dst
, ALuint samples
)
342 for(i
= 0;i
< samples
;i
++)
347 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
348 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
349 ALuint numsamples
, enum ActiveFilters type
)
355 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
356 ALfilterState_processPassthru(hpfilter
, src
, numsamples
);
360 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
361 ALfilterState_processPassthru(hpfilter
, dst
, numsamples
);
364 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
365 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
369 for(i
= 0;i
< numsamples
;)
372 ALuint todo
= minu(256, numsamples
-i
);
374 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
375 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
384 ALvoid
MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
386 ResamplerFunc Resample
;
387 ALbufferlistitem
*BufferListItem
;
388 ALuint DataPosInt
, DataPosFrac
;
397 ALuint chan
, send
, j
;
399 /* Get source info */
400 State
= AL_PLAYING
; /* Only called while playing. */
401 BufferListItem
= ATOMIC_LOAD(&Source
->current_buffer
);
402 DataPosInt
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
403 DataPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
404 Looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
405 NumChannels
= Source
->NumChannels
;
406 SampleSize
= Source
->SampleSize
;
407 increment
= voice
->Step
;
409 IrSize
= (Device
->Hrtf
.Handle
? Device
->Hrtf
.Handle
->irSize
: 0);
411 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
412 Resample_copy32_C
: ResampleSamples
);
416 ALuint SrcBufferSize
, DstBufferSize
;
427 Counter
= SamplesToDo
- OutPos
;
428 Delta
= 1.0f
/ (ALfloat
)Counter
;
431 /* Figure out how many buffer samples will be needed */
432 DataSize64
= SamplesToDo
-OutPos
;
433 DataSize64
*= increment
;
434 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
435 DataSize64
>>= FRACTIONBITS
;
436 DataSize64
+= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
438 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
440 /* Figure out how many samples we can actually mix from this. */
441 DataSize64
= SrcBufferSize
;
442 DataSize64
-= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
443 DataSize64
<<= FRACTIONBITS
;
444 DataSize64
-= DataPosFrac
;
446 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
447 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
449 /* Some mixers like having a multiple of 4, so try to give that unless
450 * this is the last update. */
451 if(OutPos
+DstBufferSize
< SamplesToDo
)
454 for(chan
= 0;chan
< NumChannels
;chan
++)
456 const ALfloat
*ResampledData
;
457 ALfloat
*SrcData
= Device
->SourceData
;
460 /* Load the previous samples into the source data first. */
461 memcpy(SrcData
, voice
->PrevSamples
[chan
], MAX_PRE_SAMPLES
*sizeof(ALfloat
));
462 SrcDataSize
= MAX_PRE_SAMPLES
;
464 if(Source
->SourceType
== AL_STATIC
)
466 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
467 const ALubyte
*Data
= ALBuffer
->data
;
471 /* Offset buffer data to current channel */
472 Data
+= chan
*SampleSize
;
474 /* If current pos is beyond the loop range, do not loop */
475 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
479 /* Load what's left to play from the source buffer, and
480 * clear the rest of the temp buffer */
482 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
484 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
485 NumChannels
, ALBuffer
->FmtType
, DataSize
);
486 SrcDataSize
+= DataSize
;
488 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
489 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
493 ALuint LoopStart
= ALBuffer
->LoopStart
;
494 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
496 /* Load what's left of this loop iteration, then load
497 * repeats of the loop section */
499 DataSize
= LoopEnd
- pos
;
500 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
502 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
503 NumChannels
, ALBuffer
->FmtType
, DataSize
);
504 SrcDataSize
+= DataSize
;
506 DataSize
= LoopEnd
-LoopStart
;
507 while(SrcBufferSize
> SrcDataSize
)
509 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
511 LoadSamples(&SrcData
[SrcDataSize
], &Data
[LoopStart
* NumChannels
*SampleSize
],
512 NumChannels
, ALBuffer
->FmtType
, DataSize
);
513 SrcDataSize
+= DataSize
;
519 /* Crawl the buffer queue to fill in the temp buffer */
520 ALbufferlistitem
*tmpiter
= BufferListItem
;
521 ALuint pos
= DataPosInt
;
523 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
525 const ALbuffer
*ALBuffer
;
526 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
528 const ALubyte
*Data
= ALBuffer
->data
;
529 ALuint DataSize
= ALBuffer
->SampleLen
;
531 /* Skip the data already played */
536 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
540 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
541 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
542 ALBuffer
->FmtType
, DataSize
);
543 SrcDataSize
+= DataSize
;
546 tmpiter
= tmpiter
->next
;
547 if(!tmpiter
&& Looping
)
548 tmpiter
= ATOMIC_LOAD(&Source
->queue
);
551 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
552 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
557 /* Store the last source samples used for next time. */
558 memcpy(voice
->PrevSamples
[chan
],
559 &SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
560 MAX_PRE_SAMPLES
*sizeof(ALfloat
)
563 /* Now resample, then filter and mix to the appropriate outputs. */
564 ResampledData
= Resample(&voice
->SincState
,
565 &SrcData
[MAX_PRE_SAMPLES
], DataPosFrac
, increment
,
566 Device
->ResampledData
, DstBufferSize
569 DirectParams
*parms
= &voice
->Chan
[chan
].Direct
;
570 const ALfloat
*samples
;
573 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
574 ResampledData
, DstBufferSize
, parms
->FilterType
578 ALfloat
*restrict currents
= parms
->Gains
.Current
;
579 const ALfloat
*targets
= parms
->Gains
.Target
;
580 MixGains gains
[MAX_OUTPUT_CHANNELS
];
584 for(j
= 0;j
< voice
->DirectOut
.Channels
;j
++)
586 gains
[j
].Target
= targets
[j
];
587 gains
[j
].Current
= gains
[j
].Target
;
588 gains
[j
].Step
= 0.0f
;
593 for(j
= 0;j
< voice
->DirectOut
.Channels
;j
++)
596 gains
[j
].Target
= targets
[j
];
597 gains
[j
].Current
= currents
[j
];
598 diff
= gains
[j
].Target
- gains
[j
].Current
;
599 if(fabsf(diff
) >= GAIN_SILENCE_THRESHOLD
)
600 gains
[j
].Step
= diff
* Delta
;
603 gains
[j
].Current
= gains
[j
].Target
;
604 gains
[j
].Step
= 0.0f
;
609 MixSamples(samples
, voice
->DirectOut
.Channels
, voice
->DirectOut
.Buffer
,
610 gains
, Counter
, OutPos
, DstBufferSize
);
612 for(j
= 0;j
< voice
->DirectOut
.Channels
;j
++)
613 currents
[j
] = gains
[j
].Current
;
617 MixHrtfParams hrtfparams
;
622 parms
->Hrtf
.Current
= parms
->Hrtf
.Target
;
623 for(j
= 0;j
< HRIR_LENGTH
;j
++)
625 hrtfparams
.Steps
.Coeffs
[j
][0] = 0.0f
;
626 hrtfparams
.Steps
.Coeffs
[j
][1] = 0.0f
;
628 hrtfparams
.Steps
.Delay
[0] = 0;
629 hrtfparams
.Steps
.Delay
[1] = 0;
635 for(j
= 0;j
< IrSize
;j
++)
637 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][0] - parms
->Hrtf
.Current
.Coeffs
[j
][0];
638 hrtfparams
.Steps
.Coeffs
[j
][0] = coeffdiff
* Delta
;
639 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][1] - parms
->Hrtf
.Current
.Coeffs
[j
][1];
640 hrtfparams
.Steps
.Coeffs
[j
][1] = coeffdiff
* Delta
;
642 delaydiff
= (ALint
)(parms
->Hrtf
.Target
.Delay
[0] - parms
->Hrtf
.Current
.Delay
[0]);
643 hrtfparams
.Steps
.Delay
[0] = fastf2i((ALfloat
)delaydiff
* Delta
);
644 delaydiff
= (ALint
)(parms
->Hrtf
.Target
.Delay
[1] - parms
->Hrtf
.Current
.Delay
[1]);
645 hrtfparams
.Steps
.Delay
[1] = fastf2i((ALfloat
)delaydiff
* Delta
);
647 hrtfparams
.Target
= &parms
->Hrtf
.Target
;
648 hrtfparams
.Current
= &parms
->Hrtf
.Current
;
650 lidx
= GetChannelIdxByName(Device
->RealOut
, FrontLeft
);
651 ridx
= GetChannelIdxByName(Device
->RealOut
, FrontRight
);
652 assert(lidx
!= -1 && ridx
!= -1);
654 MixHrtfSamples(voice
->DirectOut
.Buffer
, lidx
, ridx
, samples
, Counter
,
655 voice
->Offset
, OutPos
, IrSize
, &hrtfparams
,
656 &parms
->Hrtf
.State
, DstBufferSize
);
660 for(send
= 0;send
< Device
->NumAuxSends
;send
++)
662 SendParams
*parms
= &voice
->Chan
[chan
].Send
[send
];
663 ALfloat
*restrict currents
= parms
->Gains
.Current
;
664 const ALfloat
*targets
= parms
->Gains
.Target
;
665 MixGains gains
[MAX_OUTPUT_CHANNELS
];
666 const ALfloat
*samples
;
668 if(!voice
->SendOut
[send
].Buffer
)
672 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
673 ResampledData
, DstBufferSize
, parms
->FilterType
678 for(j
= 0;j
< voice
->SendOut
[send
].Channels
;j
++)
680 gains
[j
].Target
= targets
[j
];
681 gains
[j
].Current
= gains
[j
].Target
;
682 gains
[j
].Step
= 0.0f
;
687 for(j
= 0;j
< voice
->SendOut
[send
].Channels
;j
++)
690 gains
[j
].Target
= targets
[j
];
691 gains
[j
].Current
= currents
[j
];
692 diff
= gains
[j
].Target
- gains
[j
].Current
;
693 if(fabsf(diff
) >= GAIN_SILENCE_THRESHOLD
)
694 gains
[j
].Step
= diff
* Delta
;
697 gains
[j
].Current
= gains
[j
].Target
;
698 gains
[j
].Step
= 0.0f
;
704 voice
->SendOut
[send
].Channels
, voice
->SendOut
[send
].Buffer
,
705 gains
, Counter
, OutPos
, DstBufferSize
708 for(j
= 0;j
< voice
->SendOut
[send
].Channels
;j
++)
709 currents
[j
] = gains
[j
].Current
;
712 /* Update positions */
713 DataPosFrac
+= increment
*DstBufferSize
;
714 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
715 DataPosFrac
&= FRACTIONMASK
;
717 OutPos
+= DstBufferSize
;
718 voice
->Offset
+= DstBufferSize
;
720 /* Handle looping sources */
723 const ALbuffer
*ALBuffer
;
725 ALuint LoopStart
= 0;
728 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
730 DataSize
= ALBuffer
->SampleLen
;
731 LoopStart
= ALBuffer
->LoopStart
;
732 LoopEnd
= ALBuffer
->LoopEnd
;
733 if(LoopEnd
> DataPosInt
)
737 if(Looping
&& Source
->SourceType
== AL_STATIC
)
739 assert(LoopEnd
> LoopStart
);
740 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
744 if(DataSize
> DataPosInt
)
747 if(!(BufferListItem
=BufferListItem
->next
))
750 BufferListItem
= ATOMIC_LOAD(&Source
->queue
);
754 BufferListItem
= NULL
;
761 DataPosInt
-= DataSize
;
763 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
765 voice
->Moving
= AL_TRUE
;
767 /* Update source info */
768 Source
->state
= State
;
769 ATOMIC_STORE(&Source
->current_buffer
, BufferListItem
, almemory_order_relaxed
);
770 ATOMIC_STORE(&Source
->position
, DataPosInt
, almemory_order_relaxed
);
771 ATOMIC_STORE(&Source
->position_fraction
, DataPosFrac
);