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
*restrict frac_arr
, ALuint
*restrict 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
;
398 ALuint chan
, send
, j
;
400 /* Get source info */
401 State
= AL_PLAYING
; /* Only called while playing. */
402 BufferListItem
= ATOMIC_LOAD(&Source
->current_buffer
);
403 DataPosInt
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
404 DataPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
405 Looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
406 NumChannels
= Source
->NumChannels
;
407 SampleSize
= Source
->SampleSize
;
408 increment
= voice
->Step
;
410 IrSize
= (Device
->Hrtf
.Handle
? Device
->Hrtf
.Handle
->irSize
: 0);
412 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
413 Resample_copy32_C
: ResampleSamples
);
415 Counter
= voice
->Moving
? SamplesToDo
: 0;
418 ALuint SrcBufferSize
, DstBufferSize
;
420 /* Figure out how many buffer samples will be needed */
421 DataSize64
= SamplesToDo
-OutPos
;
422 DataSize64
*= increment
;
423 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
424 DataSize64
>>= FRACTIONBITS
;
425 DataSize64
+= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
427 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
429 /* Figure out how many samples we can actually mix from this. */
430 DataSize64
= SrcBufferSize
;
431 DataSize64
-= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
432 DataSize64
<<= FRACTIONBITS
;
433 DataSize64
-= DataPosFrac
;
435 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
436 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
438 /* Some mixers like having a multiple of 4, so try to give that unless
439 * this is the last update. */
440 if(OutPos
+DstBufferSize
< SamplesToDo
)
443 for(chan
= 0;chan
< NumChannels
;chan
++)
445 const ALfloat
*ResampledData
;
446 ALfloat
*SrcData
= Device
->SourceData
;
449 /* Load the previous samples into the source data first. */
450 memcpy(SrcData
, voice
->PrevSamples
[chan
], MAX_PRE_SAMPLES
*sizeof(ALfloat
));
451 SrcDataSize
= MAX_PRE_SAMPLES
;
453 if(Source
->SourceType
== AL_STATIC
)
455 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
456 const ALubyte
*Data
= ALBuffer
->data
;
460 /* Offset buffer data to current channel */
461 Data
+= chan
*SampleSize
;
463 /* If current pos is beyond the loop range, do not loop */
464 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
468 /* Load what's left to play from the source buffer, and
469 * clear the rest of the temp buffer */
471 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
473 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
474 NumChannels
, ALBuffer
->FmtType
, DataSize
);
475 SrcDataSize
+= DataSize
;
477 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
478 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
482 ALuint LoopStart
= ALBuffer
->LoopStart
;
483 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
485 /* Load what's left of this loop iteration, then load
486 * repeats of the loop section */
488 DataSize
= LoopEnd
- pos
;
489 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
491 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
492 NumChannels
, ALBuffer
->FmtType
, DataSize
);
493 SrcDataSize
+= DataSize
;
495 DataSize
= LoopEnd
-LoopStart
;
496 while(SrcBufferSize
> SrcDataSize
)
498 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
500 LoadSamples(&SrcData
[SrcDataSize
], &Data
[LoopStart
* NumChannels
*SampleSize
],
501 NumChannels
, ALBuffer
->FmtType
, DataSize
);
502 SrcDataSize
+= DataSize
;
508 /* Crawl the buffer queue to fill in the temp buffer */
509 ALbufferlistitem
*tmpiter
= BufferListItem
;
510 ALuint pos
= DataPosInt
;
512 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
514 const ALbuffer
*ALBuffer
;
515 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
517 const ALubyte
*Data
= ALBuffer
->data
;
518 ALuint DataSize
= ALBuffer
->SampleLen
;
520 /* Skip the data already played */
525 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
529 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
530 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
531 ALBuffer
->FmtType
, DataSize
);
532 SrcDataSize
+= DataSize
;
535 tmpiter
= tmpiter
->next
;
536 if(!tmpiter
&& Looping
)
537 tmpiter
= ATOMIC_LOAD(&Source
->queue
);
540 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
541 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
546 /* Store the last source samples used for next time. */
547 memcpy(voice
->PrevSamples
[chan
],
548 &SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
549 MAX_PRE_SAMPLES
*sizeof(ALfloat
)
552 /* Now resample, then filter and mix to the appropriate outputs. */
553 ResampledData
= Resample(&voice
->SincState
,
554 &SrcData
[MAX_PRE_SAMPLES
], DataPosFrac
, increment
,
555 Device
->ResampledData
, DstBufferSize
558 DirectParams
*parms
= &voice
->Chan
[chan
].Direct
;
559 const ALfloat
*samples
;
562 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
563 ResampledData
, DstBufferSize
, parms
->FilterType
568 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
569 sizeof(parms
->Gains
.Current
));
570 MixSamples(samples
, voice
->DirectOut
.Channels
, voice
->DirectOut
.Buffer
,
571 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
, DstBufferSize
576 MixHrtfParams hrtfparams
;
581 parms
->Hrtf
.Current
= parms
->Hrtf
.Target
;
582 for(j
= 0;j
< HRIR_LENGTH
;j
++)
584 hrtfparams
.Steps
.Coeffs
[j
][0] = 0.0f
;
585 hrtfparams
.Steps
.Coeffs
[j
][1] = 0.0f
;
587 hrtfparams
.Steps
.Delay
[0] = 0;
588 hrtfparams
.Steps
.Delay
[1] = 0;
592 ALfloat delta
= 1.0f
/ (ALfloat
)Counter
;
595 for(j
= 0;j
< IrSize
;j
++)
597 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][0] - parms
->Hrtf
.Current
.Coeffs
[j
][0];
598 hrtfparams
.Steps
.Coeffs
[j
][0] = coeffdiff
* delta
;
599 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][1] - parms
->Hrtf
.Current
.Coeffs
[j
][1];
600 hrtfparams
.Steps
.Coeffs
[j
][1] = coeffdiff
* delta
;
602 delaydiff
= (ALint
)(parms
->Hrtf
.Target
.Delay
[0] - parms
->Hrtf
.Current
.Delay
[0]);
603 hrtfparams
.Steps
.Delay
[0] = fastf2i((ALfloat
)delaydiff
* delta
);
604 delaydiff
= (ALint
)(parms
->Hrtf
.Target
.Delay
[1] - parms
->Hrtf
.Current
.Delay
[1]);
605 hrtfparams
.Steps
.Delay
[1] = fastf2i((ALfloat
)delaydiff
* delta
);
607 hrtfparams
.Target
= &parms
->Hrtf
.Target
;
608 hrtfparams
.Current
= &parms
->Hrtf
.Current
;
610 lidx
= GetChannelIdxByName(Device
->RealOut
, FrontLeft
);
611 ridx
= GetChannelIdxByName(Device
->RealOut
, FrontRight
);
612 assert(lidx
!= -1 && ridx
!= -1);
614 MixHrtfSamples(voice
->DirectOut
.Buffer
, lidx
, ridx
, samples
, Counter
,
615 voice
->Offset
, OutPos
, IrSize
, &hrtfparams
,
616 &parms
->Hrtf
.State
, DstBufferSize
);
620 for(send
= 0;send
< Device
->NumAuxSends
;send
++)
622 SendParams
*parms
= &voice
->Chan
[chan
].Send
[send
];
623 const ALfloat
*samples
;
625 if(!voice
->SendOut
[send
].Buffer
)
629 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
630 ResampledData
, DstBufferSize
, parms
->FilterType
634 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
635 sizeof(parms
->Gains
.Current
));
636 MixSamples(samples
, voice
->SendOut
[send
].Channels
, voice
->SendOut
[send
].Buffer
,
637 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
, DstBufferSize
641 /* Update positions */
642 DataPosFrac
+= increment
*DstBufferSize
;
643 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
644 DataPosFrac
&= FRACTIONMASK
;
646 OutPos
+= DstBufferSize
;
647 voice
->Offset
+= DstBufferSize
;
648 Counter
= maxu(DstBufferSize
, Counter
) - DstBufferSize
;
650 /* Handle looping sources */
653 const ALbuffer
*ALBuffer
;
655 ALuint LoopStart
= 0;
658 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
660 DataSize
= ALBuffer
->SampleLen
;
661 LoopStart
= ALBuffer
->LoopStart
;
662 LoopEnd
= ALBuffer
->LoopEnd
;
663 if(LoopEnd
> DataPosInt
)
667 if(Looping
&& Source
->SourceType
== AL_STATIC
)
669 assert(LoopEnd
> LoopStart
);
670 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
674 if(DataSize
> DataPosInt
)
677 if(!(BufferListItem
=BufferListItem
->next
))
680 BufferListItem
= ATOMIC_LOAD(&Source
->queue
);
684 BufferListItem
= NULL
;
691 DataPosInt
-= DataSize
;
693 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
695 voice
->Moving
= AL_TRUE
;
697 /* Update source info */
698 Source
->state
= State
;
699 ATOMIC_STORE(&Source
->current_buffer
, BufferListItem
, almemory_order_relaxed
);
700 ATOMIC_STORE(&Source
->position
, DataPosInt
, almemory_order_relaxed
);
701 ATOMIC_STORE(&Source
->position_fraction
, DataPosFrac
);