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
33 #include "alcontext.h"
36 #include "alListener.h"
37 #include "alAuxEffectSlot.h"
38 #include "sample_cvt.h"
41 #include "ringbuffer.h"
44 #include "mixer/defs.h"
47 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
48 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
50 /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */
51 static_assert(MAX_RESAMPLE_PADDING
>= 24, "MAX_RESAMPLE_PADDING must be at least 24!");
54 enum Resampler ResamplerDefault
= LinearResampler
;
56 MixerFunc MixSamples
= Mix_C
;
57 RowMixerFunc MixRowSamples
= MixRow_C
;
58 static HrtfMixerFunc MixHrtfSamples
= MixHrtf_C
;
59 static HrtfMixerBlendFunc MixHrtfBlendSamples
= MixHrtfBlend_C
;
61 static MixerFunc
SelectMixer(void)
64 if((CPUCapFlags
&CPU_CAP_NEON
))
68 if((CPUCapFlags
&CPU_CAP_SSE
))
74 static RowMixerFunc
SelectRowMixer(void)
77 if((CPUCapFlags
&CPU_CAP_NEON
))
81 if((CPUCapFlags
&CPU_CAP_SSE
))
87 static inline HrtfMixerFunc
SelectHrtfMixer(void)
90 if((CPUCapFlags
&CPU_CAP_NEON
))
94 if((CPUCapFlags
&CPU_CAP_SSE
))
100 static inline HrtfMixerBlendFunc
SelectHrtfBlendMixer(void)
103 if((CPUCapFlags
&CPU_CAP_NEON
))
104 return MixHrtfBlend_Neon
;
107 if((CPUCapFlags
&CPU_CAP_SSE
))
108 return MixHrtfBlend_SSE
;
110 return MixHrtfBlend_C
;
113 ResamplerFunc
SelectResampler(enum Resampler resampler
)
118 return Resample_point_C
;
119 case LinearResampler
:
121 if((CPUCapFlags
&CPU_CAP_NEON
))
122 return Resample_lerp_Neon
;
125 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
126 return Resample_lerp_SSE41
;
129 if((CPUCapFlags
&CPU_CAP_SSE2
))
130 return Resample_lerp_SSE2
;
132 return Resample_lerp_C
;
134 return Resample_cubic_C
;
135 case BSinc12Resampler
:
136 case BSinc24Resampler
:
138 if((CPUCapFlags
&CPU_CAP_NEON
))
139 return Resample_bsinc_Neon
;
142 if((CPUCapFlags
&CPU_CAP_SSE
))
143 return Resample_bsinc_SSE
;
145 return Resample_bsinc_C
;
148 return Resample_point_C
;
152 void aluInitMixer(void)
156 if(ConfigValueStr(NULL
, NULL
, "resampler", &str
))
158 if(strcasecmp(str
, "point") == 0 || strcasecmp(str
, "none") == 0)
159 ResamplerDefault
= PointResampler
;
160 else if(strcasecmp(str
, "linear") == 0)
161 ResamplerDefault
= LinearResampler
;
162 else if(strcasecmp(str
, "cubic") == 0)
163 ResamplerDefault
= FIR4Resampler
;
164 else if(strcasecmp(str
, "bsinc12") == 0)
165 ResamplerDefault
= BSinc12Resampler
;
166 else if(strcasecmp(str
, "bsinc24") == 0)
167 ResamplerDefault
= BSinc24Resampler
;
168 else if(strcasecmp(str
, "bsinc") == 0)
170 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str
);
171 ResamplerDefault
= BSinc12Resampler
;
173 else if(strcasecmp(str
, "sinc4") == 0 || strcasecmp(str
, "sinc8") == 0)
175 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
176 ResamplerDefault
= FIR4Resampler
;
181 long n
= strtol(str
, &end
, 0);
182 if(*end
== '\0' && (n
== PointResampler
|| n
== LinearResampler
|| n
== FIR4Resampler
))
183 ResamplerDefault
= static_cast<enum Resampler
>(n
);
185 WARN("Invalid resampler: %s\n", str
);
189 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
190 MixHrtfSamples
= SelectHrtfMixer();
191 MixSamples
= SelectMixer();
192 MixRowSamples
= SelectRowMixer();
198 /* Base template left undefined. Should be marked =delete, but Clang 3.8.1
199 * chokes on that given the inline specializations.
202 inline ALfloat
LoadSample(typename FmtTypeTraits
<T
>::Type val
);
204 template<> inline ALfloat LoadSample
<FmtUByte
>(FmtTypeTraits
<FmtUByte
>::Type val
)
205 { return (val
-128) * (1.0f
/128.0f
); }
206 template<> inline ALfloat LoadSample
<FmtShort
>(FmtTypeTraits
<FmtShort
>::Type val
)
207 { return val
* (1.0f
/32768.0f
); }
208 template<> inline ALfloat LoadSample
<FmtFloat
>(FmtTypeTraits
<FmtFloat
>::Type val
)
210 template<> inline ALfloat LoadSample
<FmtDouble
>(FmtTypeTraits
<FmtDouble
>::Type val
)
211 { return (ALfloat
)val
; }
212 template<> inline ALfloat LoadSample
<FmtMulaw
>(FmtTypeTraits
<FmtMulaw
>::Type val
)
213 { return muLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
214 template<> inline ALfloat LoadSample
<FmtAlaw
>(FmtTypeTraits
<FmtAlaw
>::Type val
)
215 { return aLawDecompressionTable
[val
] * (1.0f
/32768.0f
); }
218 inline void LoadSampleArray(ALfloat
*RESTRICT dst
, const void *src
, ALint srcstep
, ALsizei samples
)
220 using SampleType
= typename FmtTypeTraits
<T
>::Type
;
222 const SampleType
*ssrc
= static_cast<const SampleType
*>(src
);
223 for(ALsizei i
{0};i
< samples
;i
++)
224 dst
[i
] += LoadSample
<T
>(ssrc
[i
*srcstep
]);
227 void LoadSamples(ALfloat
*RESTRICT dst
, const ALvoid
*RESTRICT src
, ALint srcstep
, FmtType srctype
,
230 #define HANDLE_FMT(T) \
231 case T: LoadSampleArray<T>(dst, src, srcstep, samples); break
234 HANDLE_FMT(FmtUByte
);
235 HANDLE_FMT(FmtShort
);
236 HANDLE_FMT(FmtFloat
);
237 HANDLE_FMT(FmtDouble
);
238 HANDLE_FMT(FmtMulaw
);
245 const ALfloat
*DoFilters(BiquadFilter
*lpfilter
, BiquadFilter
*hpfilter
,
246 ALfloat
*RESTRICT dst
, const ALfloat
*RESTRICT src
,
247 ALsizei numsamples
, int type
)
253 BiquadFilter_passthru(lpfilter
, numsamples
);
254 BiquadFilter_passthru(hpfilter
, numsamples
);
258 BiquadFilter_process(lpfilter
, dst
, src
, numsamples
);
259 BiquadFilter_passthru(hpfilter
, numsamples
);
262 BiquadFilter_passthru(lpfilter
, numsamples
);
263 BiquadFilter_process(hpfilter
, dst
, src
, numsamples
);
267 for(i
= 0;i
< numsamples
;)
270 ALsizei todo
= mini(256, numsamples
-i
);
272 BiquadFilter_process(lpfilter
, temp
, src
+i
, todo
);
273 BiquadFilter_process(hpfilter
, dst
+i
, temp
, todo
);
283 /* This function uses these device temp buffers. */
284 #define SOURCE_DATA_BUF 0
285 #define RESAMPLED_BUF 1
286 #define FILTERED_BUF 2
287 #define NFC_DATA_BUF 3
288 ALboolean
MixSource(ALvoice
*voice
, ALuint SourceID
, ALCcontext
*Context
, ALsizei SamplesToDo
)
290 ASSUME(SamplesToDo
> 0);
292 /* Get source info */
293 bool isplaying
{true}; /* Will only be called while playing. */
294 bool isstatic
{(voice
->Flags
&VOICE_IS_STATIC
) != 0};
295 ALsizei DataPosInt
{(ALsizei
)voice
->position
.load(std::memory_order_acquire
)};
296 ALsizei DataPosFrac
{voice
->position_fraction
.load(std::memory_order_relaxed
)};
297 ALbufferlistitem
*BufferListItem
{voice
->current_buffer
.load(std::memory_order_relaxed
)};
298 ALbufferlistitem
*BufferLoopItem
{voice
->loop_buffer
.load(std::memory_order_relaxed
)};
299 ALsizei NumChannels
{voice
->NumChannels
};
300 ALsizei SampleSize
{voice
->SampleSize
};
301 ALint increment
{voice
->Step
};
303 ASSUME(DataPosInt
>= 0);
304 ASSUME(DataPosFrac
>= 0);
305 ASSUME(NumChannels
> 0);
306 ASSUME(SampleSize
> 0);
307 ASSUME(increment
> 0);
309 ALCdevice
*Device
{Context
->Device
};
310 ALsizei IrSize
{Device
->HrtfHandle
? Device
->HrtfHandle
->irSize
: 0};
312 ResamplerFunc Resample
{(increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
313 Resample_copy_C
: voice
->Resampler
};
315 ALsizei Counter
{(voice
->Flags
&VOICE_IS_FADING
) ? SamplesToDo
: 0};
316 ALsizei buffers_done
{0};
320 /* Figure out how many buffer samples will be needed */
321 ALsizei DstBufferSize
{SamplesToDo
- OutPos
};
323 /* Calculate the last written dst sample pos. */
324 ALint64 DataSize64
{DstBufferSize
- 1};
325 /* Calculate the last read src sample pos. */
326 DataSize64
= (DataSize64
*increment
+ DataPosFrac
) >> FRACTIONBITS
;
327 /* +1 to get the src sample count, include padding. */
328 DataSize64
+= 1 + MAX_RESAMPLE_PADDING
*2;
330 auto SrcBufferSize
= static_cast<ALsizei
>(mini64(DataSize64
, BUFFERSIZE
+1));
331 if(SrcBufferSize
> BUFFERSIZE
)
333 SrcBufferSize
= BUFFERSIZE
;
334 /* If the source buffer got saturated, we can't fill the desired
335 * dst size. Figure out how many samples we can actually mix from
338 DataSize64
= SrcBufferSize
- MAX_RESAMPLE_PADDING
*2;
339 DataSize64
= ((DataSize64
<<FRACTIONBITS
) - DataPosFrac
+ increment
-1) / increment
;
340 DstBufferSize
= static_cast<ALsizei
>(mini64(DataSize64
, DstBufferSize
));
342 /* Some mixers like having a multiple of 4, so try to give that
343 * unless this is the last update.
345 if(DstBufferSize
< SamplesToDo
-OutPos
)
349 /* It's impossible to have a buffer list item with no entries. */
350 assert(BufferListItem
->num_buffers
> 0);
352 for(ALsizei chan
{0};chan
< NumChannels
;chan
++)
354 ALfloat (&SrcData
)[BUFFERSIZE
] = Device
->TempBuffer
[SOURCE_DATA_BUF
];
356 /* Load the previous samples into the source data first, and clear the rest. */
357 auto srciter
= std::copy(std::begin(voice
->PrevSamples
[chan
]),
358 std::end(voice
->PrevSamples
[chan
]), std::begin(SrcData
));
359 std::fill(srciter
, std::end(SrcData
), 0.0f
);
361 auto FilledAmt
= static_cast<ALsizei
>(voice
->PrevSamples
[chan
].size());
364 /* TODO: For static sources, loop points are taken from the
365 * first buffer (should be adjusted by any buffer offset, to
366 * possibly be added later).
368 const ALbuffer
*Buffer0
{BufferListItem
->buffers
[0]};
369 const ALsizei LoopStart
{Buffer0
->LoopStart
};
370 const ALsizei LoopEnd
{Buffer0
->LoopEnd
};
371 ASSUME(LoopStart
>= 0);
372 ASSUME(LoopEnd
> LoopStart
);
374 /* If current pos is beyond the loop range, do not loop */
375 if(!BufferLoopItem
|| DataPosInt
>= LoopEnd
)
377 ALsizei SizeToDo
= SrcBufferSize
- FilledAmt
;
379 BufferLoopItem
= nullptr;
382 auto load_buffer
= [DataPosInt
,&SrcData
,NumChannels
,SampleSize
,chan
,FilledAmt
,SizeToDo
,&CompLen
](const ALbuffer
*buffer
) -> void
384 if(DataPosInt
>= buffer
->SampleLen
)
387 /* Load what's left to play from the buffer */
388 ALsizei DataSize
{mini(SizeToDo
, buffer
->SampleLen
- DataPosInt
)};
389 CompLen
= maxi(CompLen
, DataSize
);
391 const ALbyte
*Data
{buffer
->mData
.data()};
392 LoadSamples(&SrcData
[FilledAmt
],
393 &Data
[(DataPosInt
*NumChannels
+ chan
)*SampleSize
],
394 NumChannels
, buffer
->FmtType
, DataSize
397 auto buffers_end
= BufferListItem
->buffers
+ BufferListItem
->num_buffers
;
398 std::for_each(BufferListItem
->buffers
, buffers_end
, load_buffer
);
399 FilledAmt
+= CompLen
;
403 const ALsizei SizeToDo
{mini(SrcBufferSize
- FilledAmt
, LoopEnd
- DataPosInt
)};
406 auto load_buffer
= [DataPosInt
,&SrcData
,NumChannels
,SampleSize
,chan
,FilledAmt
,SizeToDo
,&CompLen
](const ALbuffer
*buffer
) -> void
408 if(DataPosInt
>= buffer
->SampleLen
)
411 /* Load what's left of this loop iteration */
412 ALsizei DataSize
{mini(SizeToDo
, buffer
->SampleLen
- DataPosInt
)};
413 CompLen
= maxi(CompLen
, DataSize
);
415 const ALbyte
*Data
{buffer
->mData
.data()};
416 LoadSamples(&SrcData
[FilledAmt
],
417 &Data
[(DataPosInt
*NumChannels
+ chan
)*SampleSize
],
418 NumChannels
, buffer
->FmtType
, DataSize
421 auto buffers_end
= BufferListItem
->buffers
+ BufferListItem
->num_buffers
;
422 std::for_each(BufferListItem
->buffers
, buffers_end
, load_buffer
);
423 FilledAmt
+= CompLen
;
425 const ALsizei LoopSize
{LoopEnd
- LoopStart
};
426 while(SrcBufferSize
> FilledAmt
)
428 const ALsizei SizeToDo
{mini(SrcBufferSize
- FilledAmt
, LoopSize
)};
431 auto load_buffer_loop
= [LoopStart
,&SrcData
,NumChannels
,SampleSize
,chan
,FilledAmt
,SizeToDo
,&CompLen
](const ALbuffer
*buffer
) -> void
433 const ALbyte
*Data
= buffer
->mData
.data();
436 if(LoopStart
>= buffer
->SampleLen
)
439 DataSize
= mini(SizeToDo
, buffer
->SampleLen
- LoopStart
);
440 CompLen
= maxi(CompLen
, DataSize
);
442 LoadSamples(&SrcData
[FilledAmt
],
443 &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
444 NumChannels
, buffer
->FmtType
, DataSize
447 std::for_each(BufferListItem
->buffers
, buffers_end
, load_buffer_loop
);
448 FilledAmt
+= CompLen
;
454 /* Crawl the buffer queue to fill in the temp buffer */
455 ALbufferlistitem
*tmpiter
{BufferListItem
};
456 ALsizei pos
{DataPosInt
};
458 while(tmpiter
&& SrcBufferSize
> FilledAmt
)
460 if(pos
>= tmpiter
->max_samples
)
462 pos
-= tmpiter
->max_samples
;
463 tmpiter
= tmpiter
->next
.load(std::memory_order_acquire
);
464 if(!tmpiter
) tmpiter
= BufferLoopItem
;
468 const ALsizei SizeToDo
{SrcBufferSize
- FilledAmt
};
470 auto load_buffer
= [pos
,&SrcData
,NumChannels
,SampleSize
,chan
,FilledAmt
,SizeToDo
,&CompLen
](const ALbuffer
*buffer
) -> void
473 ALsizei DataSize
{buffer
->SampleLen
};
474 if(pos
>= DataSize
) return;
476 DataSize
= mini(SizeToDo
, DataSize
- pos
);
477 CompLen
= maxi(CompLen
, DataSize
);
479 const ALbyte
*Data
{buffer
->mData
.data()};
480 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
482 LoadSamples(&SrcData
[FilledAmt
], Data
, NumChannels
,
483 buffer
->FmtType
, DataSize
);
485 auto buffers_end
= tmpiter
->buffers
+ tmpiter
->num_buffers
;
486 std::for_each(tmpiter
->buffers
, buffers_end
, load_buffer
);
487 FilledAmt
+= CompLen
;
489 if(SrcBufferSize
<= FilledAmt
)
492 tmpiter
= tmpiter
->next
.load(std::memory_order_acquire
);
493 if(!tmpiter
) tmpiter
= BufferLoopItem
;
497 /* Store the last source samples used for next time. */
498 std::copy_n(&SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
499 voice
->PrevSamples
[chan
].size(), std::begin(voice
->PrevSamples
[chan
]));
501 /* Now resample, then filter and mix to the appropriate outputs. */
502 const ALfloat
*ResampledData
{Resample(&voice
->ResampleState
,
503 &SrcData
[MAX_RESAMPLE_PADDING
], DataPosFrac
, increment
,
504 Device
->TempBuffer
[RESAMPLED_BUF
], DstBufferSize
507 DirectParams
*parms
{&voice
->Direct
.Params
[chan
]};
508 const ALfloat
*samples
{DoFilters(&parms
->LowPass
, &parms
->HighPass
,
509 Device
->TempBuffer
[FILTERED_BUF
], ResampledData
, DstBufferSize
,
510 voice
->Direct
.FilterType
513 if(!(voice
->Flags
&VOICE_HAS_HRTF
))
516 std::copy(std::begin(parms
->Gains
.Target
), std::end(parms
->Gains
.Target
),
517 std::begin(parms
->Gains
.Current
));
519 if(!(voice
->Flags
&VOICE_HAS_NFC
))
520 MixSamples(samples
, voice
->Direct
.Channels
, voice
->Direct
.Buffer
,
521 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
527 voice
->Direct
.ChannelsPerOrder
[0], voice
->Direct
.Buffer
,
528 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
532 ALfloat
*nfcsamples
{Device
->TempBuffer
[NFC_DATA_BUF
]};
533 ALsizei chanoffset
{voice
->Direct
.ChannelsPerOrder
[0]};
534 using FilterProc
= void(NfcFilter
*,ALfloat
*,const ALfloat
*,ALsizei
);
535 auto apply_nfc
= [voice
,parms
,samples
,DstBufferSize
,Counter
,OutPos
,&chanoffset
,nfcsamples
](FilterProc
&process
, ALsizei order
) -> void
537 if(voice
->Direct
.ChannelsPerOrder
[order
] < 1)
539 process(&parms
->NFCtrlFilter
, nfcsamples
, samples
, DstBufferSize
);
540 MixSamples(nfcsamples
, voice
->Direct
.ChannelsPerOrder
[order
],
541 voice
->Direct
.Buffer
+chanoffset
, parms
->Gains
.Current
+chanoffset
,
542 parms
->Gains
.Target
+chanoffset
, Counter
, OutPos
, DstBufferSize
544 chanoffset
+= voice
->Direct
.ChannelsPerOrder
[order
];
546 apply_nfc(NfcFilterProcess1
, 1);
547 apply_nfc(NfcFilterProcess2
, 2);
548 apply_nfc(NfcFilterProcess3
, 3);
553 MixHrtfParams hrtfparams
;
557 lidx
= GetChannelIdxByName(&Device
->RealOut
, FrontLeft
);
558 ridx
= GetChannelIdxByName(&Device
->RealOut
, FrontRight
);
559 assert(lidx
!= -1 && ridx
!= -1);
563 /* No fading, just overwrite the old HRTF params. */
564 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
566 else if(!(parms
->Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
568 /* The old HRTF params are silent, so overwrite the old
569 * coefficients with the new, and reset the old gain to
570 * 0. The future mix will then fade from silence.
572 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
573 parms
->Hrtf
.Old
.Gain
= 0.0f
;
577 /* First mixing pass, fade between the coefficients. */
578 fademix
= mini(DstBufferSize
, 128);
580 /* The new coefficients need to fade in completely
581 * since they're replacing the old ones. To keep the
582 * gain fading consistent, interpolate between the old
583 * and new target gains given how much of the fade time
586 ALfloat gain
{lerp(parms
->Hrtf
.Old
.Gain
, parms
->Hrtf
.Target
.Gain
,
587 minf(1.0f
, (ALfloat
)fademix
/Counter
))};
588 hrtfparams
.Coeffs
= parms
->Hrtf
.Target
.Coeffs
;
589 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
590 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
591 hrtfparams
.Gain
= 0.0f
;
592 hrtfparams
.GainStep
= gain
/ (ALfloat
)fademix
;
595 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
596 samples
, voice
->Offset
, OutPos
, IrSize
, &parms
->Hrtf
.Old
,
597 &hrtfparams
, &parms
->Hrtf
.State
, fademix
599 /* Update the old parameters with the result. */
600 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
601 if(fademix
< Counter
)
602 parms
->Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
605 if(fademix
< DstBufferSize
)
607 ALsizei todo
= DstBufferSize
- fademix
;
608 ALfloat gain
= parms
->Hrtf
.Target
.Gain
;
610 /* Interpolate the target gain if the gain fading lasts
611 * longer than this mix.
613 if(Counter
> DstBufferSize
)
614 gain
= lerp(parms
->Hrtf
.Old
.Gain
, gain
,
615 (ALfloat
)todo
/(Counter
-fademix
));
617 hrtfparams
.Coeffs
= parms
->Hrtf
.Target
.Coeffs
;
618 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
619 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
620 hrtfparams
.Gain
= parms
->Hrtf
.Old
.Gain
;
621 hrtfparams
.GainStep
= (gain
- parms
->Hrtf
.Old
.Gain
) / (ALfloat
)todo
;
623 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
624 samples
+fademix
, voice
->Offset
+fademix
, OutPos
+fademix
, IrSize
,
625 &hrtfparams
, &parms
->Hrtf
.State
, todo
627 /* Store the interpolated gain or the final target gain
628 * depending if the fade is done.
630 if(DstBufferSize
< Counter
)
631 parms
->Hrtf
.Old
.Gain
= gain
;
633 parms
->Hrtf
.Old
.Gain
= parms
->Hrtf
.Target
.Gain
;
638 ALfloat (&FilterBuf
)[BUFFERSIZE
] = Device
->TempBuffer
[FILTERED_BUF
];
639 auto mix_send
= [Counter
,OutPos
,DstBufferSize
,chan
,ResampledData
,&FilterBuf
](ALvoice::SendData
&send
) -> void
644 SendParams
*parms
= &send
.Params
[chan
];
645 const ALfloat
*samples
{DoFilters(&parms
->LowPass
, &parms
->HighPass
,
646 FilterBuf
, ResampledData
, DstBufferSize
, send
.FilterType
650 std::copy(std::begin(parms
->Gains
.Target
), std::end(parms
->Gains
.Target
),
651 std::begin(parms
->Gains
.Current
));
652 MixSamples(samples
, send
.Channels
, send
.Buffer
,
653 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
, DstBufferSize
656 std::for_each(voice
->Send
, voice
->Send
+Device
->NumAuxSends
, mix_send
);
658 /* Update positions */
659 DataPosFrac
+= increment
*DstBufferSize
;
660 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
661 DataPosFrac
&= FRACTIONMASK
;
663 OutPos
+= DstBufferSize
;
664 voice
->Offset
+= DstBufferSize
;
665 Counter
= maxi(DstBufferSize
, Counter
) - DstBufferSize
;
671 /* Handle looping static source */
672 const ALbuffer
*Buffer
{BufferListItem
->buffers
[0]};
673 ALsizei LoopStart
{Buffer
->LoopStart
};
674 ALsizei LoopEnd
{Buffer
->LoopEnd
};
675 if(DataPosInt
>= LoopEnd
)
677 assert(LoopEnd
> LoopStart
);
678 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
683 /* Handle non-looping static source */
684 if(DataPosInt
>= BufferListItem
->max_samples
)
687 BufferListItem
= NULL
;
696 /* Handle streaming source */
697 if(BufferListItem
->max_samples
> DataPosInt
)
700 DataPosInt
-= BufferListItem
->max_samples
;
702 buffers_done
+= BufferListItem
->num_buffers
;
703 BufferListItem
= BufferListItem
->next
.load(std::memory_order_relaxed
);
704 if(!BufferListItem
&& !(BufferListItem
=BufferLoopItem
))
712 } while(isplaying
&& OutPos
< SamplesToDo
);
714 voice
->Flags
|= VOICE_IS_FADING
;
716 /* Update source info */
717 voice
->position
.store(DataPosInt
, std::memory_order_relaxed
);
718 voice
->position_fraction
.store(DataPosFrac
, std::memory_order_relaxed
);
719 voice
->current_buffer
.store(BufferListItem
, std::memory_order_release
);
721 /* Send any events now, after the position/buffer info was updated. */
722 ALbitfieldSOFT enabledevt
{Context
->EnabledEvts
.load(std::memory_order_acquire
)};
723 if(buffers_done
> 0 && (enabledevt
&EventType_BufferCompleted
))
725 AsyncEvent evt
{ASYNC_EVENT(EventType_BufferCompleted
)};
726 evt
.u
.bufcomp
.id
= SourceID
;
727 evt
.u
.bufcomp
.count
= buffers_done
;
728 if(ll_ringbuffer_write(Context
->AsyncEvents
, &evt
, 1) == 1)
729 Context
->EventSem
.post();