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_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, ALint srcstep, ALsizei 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
, ALint srcstep
, enum FmtType srctype
, ALsizei 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
, ALsizei 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 ALsizei 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 ALsizei todo
= mini(256, numsamples
-i
);
374 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
375 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
384 void MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALsizei SamplesToDo
)
386 ResamplerFunc Resample
;
387 ALbufferlistitem
*BufferListItem
;
388 ALuint DataPosInt
, DataPosFrac
;
401 /* Get source info */
402 State
= AL_PLAYING
; /* Only called while playing. */
403 BufferListItem
= ATOMIC_LOAD(&Source
->current_buffer
, almemory_order_acquire
);
404 DataPosInt
= ATOMIC_LOAD(&Source
->position
, almemory_order_relaxed
);
405 DataPosFrac
= ATOMIC_LOAD(&Source
->position_fraction
, almemory_order_relaxed
);
406 Looping
= ATOMIC_LOAD(&Source
->looping
, almemory_order_relaxed
);
407 NumChannels
= Source
->NumChannels
;
408 SampleSize
= Source
->SampleSize
;
409 increment
= voice
->Step
;
411 IrSize
= (Device
->Hrtf
.Handle
? Device
->Hrtf
.Handle
->irSize
: 0);
413 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
414 Resample_copy32_C
: ResampleSamples
);
416 Counter
= voice
->Moving
? SamplesToDo
: 0;
419 ALsizei SrcBufferSize
, DstBufferSize
;
421 /* Figure out how many buffer samples will be needed */
422 DataSize64
= SamplesToDo
-OutPos
;
423 DataSize64
*= increment
;
424 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
425 DataSize64
>>= FRACTIONBITS
;
426 DataSize64
+= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
428 SrcBufferSize
= (ALsizei
)mini64(DataSize64
, BUFFERSIZE
);
430 /* Figure out how many samples we can actually mix from this. */
431 DataSize64
= SrcBufferSize
;
432 DataSize64
-= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
433 DataSize64
<<= FRACTIONBITS
;
434 DataSize64
-= DataPosFrac
;
436 DstBufferSize
= (ALsizei
)((DataSize64
+(increment
-1)) / increment
);
437 DstBufferSize
= mini(DstBufferSize
, (SamplesToDo
-OutPos
));
439 /* Some mixers like having a multiple of 4, so try to give that unless
440 * this is the last update. */
441 if(OutPos
+DstBufferSize
< SamplesToDo
)
444 for(chan
= 0;chan
< NumChannels
;chan
++)
446 const ALfloat
*ResampledData
;
447 ALfloat
*SrcData
= Device
->SourceData
;
450 /* Load the previous samples into the source data first. */
451 memcpy(SrcData
, voice
->PrevSamples
[chan
], MAX_PRE_SAMPLES
*sizeof(ALfloat
));
452 SrcDataSize
= MAX_PRE_SAMPLES
;
454 if(Source
->SourceType
== AL_STATIC
)
456 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
457 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 */
470 DataSize
= minu(SrcBufferSize
- SrcDataSize
,
471 ALBuffer
->SampleLen
- DataPosInt
);
473 LoadSamples(&SrcData
[SrcDataSize
], &Data
[DataPosInt
* NumChannels
*SampleSize
],
474 NumChannels
, ALBuffer
->FmtType
, DataSize
);
475 SrcDataSize
+= DataSize
;
477 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
478 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
482 ALsizei LoopStart
= ALBuffer
->LoopStart
;
483 ALsizei LoopEnd
= ALBuffer
->LoopEnd
;
485 /* Load what's left of this loop iteration, then load
486 * repeats of the loop section */
487 DataSize
= minu(SrcBufferSize
- SrcDataSize
, LoopEnd
- DataPosInt
);
489 LoadSamples(&SrcData
[SrcDataSize
], &Data
[DataPosInt
* NumChannels
*SampleSize
],
490 NumChannels
, ALBuffer
->FmtType
, DataSize
);
491 SrcDataSize
+= DataSize
;
493 DataSize
= LoopEnd
-LoopStart
;
494 while(SrcBufferSize
> SrcDataSize
)
496 DataSize
= mini(SrcBufferSize
- SrcDataSize
, DataSize
);
498 LoadSamples(&SrcData
[SrcDataSize
], &Data
[LoopStart
* NumChannels
*SampleSize
],
499 NumChannels
, ALBuffer
->FmtType
, DataSize
);
500 SrcDataSize
+= DataSize
;
506 /* Crawl the buffer queue to fill in the temp buffer */
507 ALbufferlistitem
*tmpiter
= BufferListItem
;
508 ALuint pos
= DataPosInt
;
510 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
512 const ALbuffer
*ALBuffer
;
513 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
515 const ALubyte
*Data
= ALBuffer
->data
;
516 ALuint DataSize
= ALBuffer
->SampleLen
;
518 /* Skip the data already played */
523 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
527 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
528 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
529 ALBuffer
->FmtType
, DataSize
);
530 SrcDataSize
+= DataSize
;
533 tmpiter
= tmpiter
->next
;
534 if(!tmpiter
&& Looping
)
535 tmpiter
= ATOMIC_LOAD(&Source
->queue
, almemory_order_acquire
);
538 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
539 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
544 /* Store the last source samples used for next time. */
545 memcpy(voice
->PrevSamples
[chan
],
546 &SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
547 MAX_PRE_SAMPLES
*sizeof(ALfloat
)
550 /* Now resample, then filter and mix to the appropriate outputs. */
551 ResampledData
= Resample(&voice
->SincState
,
552 &SrcData
[MAX_PRE_SAMPLES
], DataPosFrac
, increment
,
553 Device
->ResampledData
, DstBufferSize
556 DirectParams
*parms
= &voice
->Chan
[chan
].Direct
;
557 const ALfloat
*samples
;
560 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
561 ResampledData
, DstBufferSize
, parms
->FilterType
566 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
567 sizeof(parms
->Gains
.Current
));
568 MixSamples(samples
, voice
->DirectOut
.Channels
, voice
->DirectOut
.Buffer
,
569 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
, DstBufferSize
574 MixHrtfParams hrtfparams
;
579 parms
->Hrtf
.Current
= parms
->Hrtf
.Target
;
580 for(j
= 0;j
< HRIR_LENGTH
;j
++)
582 hrtfparams
.Steps
.Coeffs
[j
][0] = 0.0f
;
583 hrtfparams
.Steps
.Coeffs
[j
][1] = 0.0f
;
585 hrtfparams
.Steps
.Delay
[0] = 0;
586 hrtfparams
.Steps
.Delay
[1] = 0;
590 ALfloat delta
= 1.0f
/ (ALfloat
)Counter
;
593 for(j
= 0;j
< IrSize
;j
++)
595 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][0] - parms
->Hrtf
.Current
.Coeffs
[j
][0];
596 hrtfparams
.Steps
.Coeffs
[j
][0] = coeffdiff
* delta
;
597 coeffdiff
= parms
->Hrtf
.Target
.Coeffs
[j
][1] - parms
->Hrtf
.Current
.Coeffs
[j
][1];
598 hrtfparams
.Steps
.Coeffs
[j
][1] = coeffdiff
* delta
;
600 delaydiff
= parms
->Hrtf
.Target
.Delay
[0] - parms
->Hrtf
.Current
.Delay
[0];
601 hrtfparams
.Steps
.Delay
[0] = fastf2i((ALfloat
)delaydiff
* delta
);
602 delaydiff
= parms
->Hrtf
.Target
.Delay
[1] - parms
->Hrtf
.Current
.Delay
[1];
603 hrtfparams
.Steps
.Delay
[1] = fastf2i((ALfloat
)delaydiff
* delta
);
605 hrtfparams
.Target
= &parms
->Hrtf
.Target
;
606 hrtfparams
.Current
= &parms
->Hrtf
.Current
;
608 lidx
= GetChannelIdxByName(Device
->RealOut
, FrontLeft
);
609 ridx
= GetChannelIdxByName(Device
->RealOut
, FrontRight
);
610 assert(lidx
!= -1 && ridx
!= -1);
613 voice
->DirectOut
.Buffer
[lidx
], voice
->DirectOut
.Buffer
[ridx
],
614 samples
, Counter
, voice
->Offset
, OutPos
, IrSize
, &hrtfparams
,
615 &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
= maxi(DstBufferSize
, Counter
) - DstBufferSize
;
650 /* Handle looping sources */
653 const ALbuffer
*ALBuffer
;
654 ALsizei DataSize
= 0;
655 ALsizei LoopStart
= 0;
658 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
660 DataSize
= ALBuffer
->SampleLen
;
661 LoopStart
= ALBuffer
->LoopStart
;
662 LoopEnd
= ALBuffer
->LoopEnd
;
663 if((ALuint
)LoopEnd
> DataPosInt
)
667 if(Looping
&& Source
->SourceType
== AL_STATIC
)
669 assert(LoopEnd
> LoopStart
);
670 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
674 if((ALuint
)DataSize
> DataPosInt
)
677 if(!(BufferListItem
=BufferListItem
->next
))
680 BufferListItem
= ATOMIC_LOAD(&Source
->queue
, almemory_order_acquire
);
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
, almemory_order_release
);