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
, ALint increment
, ALuint
*restrict frac_arr
, ALint
*restrict pos_arr
, ALsizei 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_NEON
))
118 return Resample_lerp32_Neon
;
121 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
122 return Resample_lerp32_SSE41
;
125 if((CPUCapFlags
&CPU_CAP_SSE2
))
126 return Resample_lerp32_SSE2
;
128 return Resample_lerp32_C
;
131 if((CPUCapFlags
&CPU_CAP_NEON
))
132 return Resample_fir4_32_Neon
;
135 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
136 return Resample_fir4_32_SSE41
;
139 if((CPUCapFlags
&CPU_CAP_SSE3
))
140 return Resample_fir4_32_SSE3
;
142 return Resample_fir4_32_C
;
145 if((CPUCapFlags
&CPU_CAP_NEON
))
146 return Resample_fir8_32_Neon
;
149 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
150 return Resample_fir8_32_SSE41
;
153 if((CPUCapFlags
&CPU_CAP_SSE3
))
154 return Resample_fir8_32_SSE3
;
156 return Resample_fir8_32_C
;
159 if((CPUCapFlags
&CPU_CAP_NEON
))
160 return Resample_bsinc32_Neon
;
163 if((CPUCapFlags
&CPU_CAP_SSE
))
164 return Resample_bsinc32_SSE
;
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.
178 #define M_PI (3.14159265358979323846)
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
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
;
197 /* Start at k=1 since k=0 is trivial. */
203 /* Let the integration converge until the term of the sum is no longer
212 } while(sum
!= last_sum
);
216 /* Calculate a Kaiser window from the given beta value and a normalized k
219 * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
222 * Where k can be calculated as:
224 * k = i / l, where -l <= i <= l.
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
)
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));
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
;
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
;
279 long n
= strtol(str
, &end
, 0);
280 if(*end
== '\0' && (n
== PointResampler
|| n
== LinearResampler
|| n
== FIR4Resampler
))
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
)
325 #define DECL_TEMPLATE(T) \
326 static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\
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
)
339 static void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALint srcstep
, enum FmtType srctype
, ALsizei samples
)
344 Load_ALbyte(dst
, src
, srcstep
, samples
);
347 Load_ALshort(dst
, src
, srcstep
, samples
);
350 Load_ALfloat(dst
, src
, srcstep
, samples
);
355 static inline void SilenceSamples(ALfloat
*dst
, ALsizei samples
)
358 for(i
= 0;i
< samples
;i
++)
363 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
364 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
365 ALsizei numsamples
, enum ActiveFilters type
)
371 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
372 ALfilterState_processPassthru(hpfilter
, src
, numsamples
);
376 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
377 ALfilterState_processPassthru(hpfilter
, dst
, numsamples
);
380 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
381 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
385 for(i
= 0;i
< numsamples
;)
388 ALsizei todo
= mini(256, numsamples
-i
);
390 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
391 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
400 void MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALsizei SamplesToDo
)
402 ResamplerFunc Resample
;
403 ALbufferlistitem
*BufferListItem
;
404 ALuint DataPosInt
, DataPosFrac
;
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;
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
)
460 for(chan
= 0;chan
< NumChannels
;chan
++)
462 const ALfloat
*ResampledData
;
463 ALfloat
*SrcData
= Device
->SourceData
;
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
;
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
)
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
;
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
;
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 */
539 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
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
);
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
;
576 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
577 ResampledData
, DstBufferSize
, parms
->FilterType
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
590 MixHrtfParams hrtfparams
;
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;
606 ALfloat delta
= 1.0f
/ (ALfloat
)Counter
;
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);
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
)
645 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
646 ResampledData
, DstBufferSize
, parms
->FilterType
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 */
669 const ALbuffer
*ALBuffer
;
670 ALsizei DataSize
= 0;
671 ALsizei LoopStart
= 0;
674 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
676 DataSize
= ALBuffer
->SampleLen
;
677 LoopStart
= ALBuffer
->LoopStart
;
678 LoopEnd
= ALBuffer
->LoopEnd
;
679 if((ALuint
)LoopEnd
> DataPosInt
)
683 if(Looping
&& Source
->SourceType
== AL_STATIC
)
685 assert(LoopEnd
> LoopStart
);
686 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
690 if((ALuint
)DataSize
> DataPosInt
)
693 if(!(BufferListItem
=BufferListItem
->next
))
696 BufferListItem
= ATOMIC_LOAD(&Source
->queue
, almemory_order_acquire
);
700 BufferListItem
= NULL
;
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
);