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(ALsizei frac
, ALint increment
, ALsizei
*restrict frac_arr
, ALint
*restrict pos_arr
, ALsizei size
);
47 /* BSinc requires up to 11 extra samples before the current position, and 12 after. */
48 static_assert(MAX_PRE_SAMPLES
>= 11, "MAX_PRE_SAMPLES must be at least 11!");
49 static_assert(MAX_POST_SAMPLES
>= 12, "MAX_POST_SAMPLES must be at least 12!");
52 enum Resampler ResamplerDefault
= LinearResampler
;
54 static MixerFunc MixSamples
= Mix_C
;
55 static HrtfMixerFunc MixHrtfSamples
= MixHrtf_C
;
57 MixerFunc
SelectMixer(void)
60 if((CPUCapFlags
&CPU_CAP_NEON
))
64 if((CPUCapFlags
&CPU_CAP_SSE
))
70 RowMixerFunc
SelectRowMixer(void)
73 if((CPUCapFlags
&CPU_CAP_NEON
))
77 if((CPUCapFlags
&CPU_CAP_SSE
))
83 static inline HrtfMixerFunc
SelectHrtfMixer(void)
86 if((CPUCapFlags
&CPU_CAP_NEON
))
90 if((CPUCapFlags
&CPU_CAP_SSE
))
97 ResamplerFunc
SelectResampler(enum Resampler resampler
)
102 return Resample_point32_C
;
103 case LinearResampler
:
105 if((CPUCapFlags
&CPU_CAP_NEON
))
106 return Resample_lerp32_Neon
;
109 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
110 return Resample_lerp32_SSE41
;
113 if((CPUCapFlags
&CPU_CAP_SSE2
))
114 return Resample_lerp32_SSE2
;
116 return Resample_lerp32_C
;
119 if((CPUCapFlags
&CPU_CAP_NEON
))
120 return Resample_fir4_32_Neon
;
123 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
124 return Resample_fir4_32_SSE41
;
127 if((CPUCapFlags
&CPU_CAP_SSE3
))
128 return Resample_fir4_32_SSE3
;
130 return Resample_fir4_32_C
;
133 if((CPUCapFlags
&CPU_CAP_NEON
))
134 return Resample_bsinc32_Neon
;
137 if((CPUCapFlags
&CPU_CAP_SSE
))
138 return Resample_bsinc32_SSE
;
140 return Resample_bsinc32_C
;
143 return Resample_point32_C
;
147 void aluInitMixer(void)
151 if(ConfigValueStr(NULL
, NULL
, "resampler", &str
))
153 if(strcasecmp(str
, "point") == 0 || strcasecmp(str
, "none") == 0)
154 ResamplerDefault
= PointResampler
;
155 else if(strcasecmp(str
, "linear") == 0)
156 ResamplerDefault
= LinearResampler
;
157 else if(strcasecmp(str
, "sinc4") == 0)
158 ResamplerDefault
= FIR4Resampler
;
159 else if(strcasecmp(str
, "bsinc") == 0)
160 ResamplerDefault
= BSincResampler
;
161 else if(strcasecmp(str
, "cubic") == 0 || strcasecmp(str
, "sinc8") == 0)
163 WARN("Resampler option \"%s\" is deprecated, using sinc4\n", str
);
164 ResamplerDefault
= FIR4Resampler
;
169 long n
= strtol(str
, &end
, 0);
170 if(*end
== '\0' && (n
== PointResampler
|| n
== LinearResampler
|| n
== FIR4Resampler
))
171 ResamplerDefault
= n
;
173 WARN("Invalid resampler: %s\n", str
);
177 MixHrtfSamples
= SelectHrtfMixer();
178 MixSamples
= SelectMixer();
182 static inline ALfloat
Sample_ALbyte(ALbyte val
)
183 { return val
* (1.0f
/128.0f
); }
185 static inline ALfloat
Sample_ALshort(ALshort val
)
186 { return val
* (1.0f
/32768.0f
); }
188 static inline ALfloat
Sample_ALfloat(ALfloat val
)
191 #define DECL_TEMPLATE(T) \
192 static inline void Load_##T(ALfloat *dst, const T *src, ALint srcstep, ALsizei samples)\
195 for(i = 0;i < samples;i++) \
196 dst[i] = Sample_##T(src[i*srcstep]); \
199 DECL_TEMPLATE(ALbyte
)
200 DECL_TEMPLATE(ALshort
)
201 DECL_TEMPLATE(ALfloat
)
205 static void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALint srcstep
, enum FmtType srctype
, ALsizei samples
)
210 Load_ALbyte(dst
, src
, srcstep
, samples
);
213 Load_ALshort(dst
, src
, srcstep
, samples
);
216 Load_ALfloat(dst
, src
, srcstep
, samples
);
221 static inline void SilenceSamples(ALfloat
*dst
, ALsizei samples
)
224 for(i
= 0;i
< samples
;i
++)
229 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
230 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
231 ALsizei numsamples
, enum ActiveFilters type
)
237 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
238 ALfilterState_processPassthru(hpfilter
, src
, numsamples
);
242 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
243 ALfilterState_processPassthru(hpfilter
, dst
, numsamples
);
246 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
247 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
251 for(i
= 0;i
< numsamples
;)
254 ALsizei todo
= mini(256, numsamples
-i
);
256 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
257 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
266 ALboolean
MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALsizei SamplesToDo
)
268 ALbufferlistitem
*BufferListItem
;
269 ALbufferlistitem
*BufferLoopItem
;
270 ALsizei NumChannels
, SampleSize
;
271 ResamplerFunc Resample
;
284 /* Get source info */
285 isplaying
= true; /* Will only be called while playing. */
286 DataPosInt
= ATOMIC_LOAD(&voice
->position
, almemory_order_acquire
);
287 DataPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
288 BufferListItem
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
289 BufferLoopItem
= ATOMIC_LOAD(&voice
->loop_buffer
, almemory_order_relaxed
);
290 NumChannels
= voice
->NumChannels
;
291 SampleSize
= voice
->SampleSize
;
292 increment
= voice
->Step
;
294 IrSize
= (Device
->HrtfHandle
? Device
->HrtfHandle
->irSize
: 0);
296 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
297 Resample_copy32_C
: voice
->Resampler
);
299 Counter
= (voice
->Flags
&VOICE_IS_FADING
) ? SamplesToDo
: 0;
304 ALsizei SrcBufferSize
, DstBufferSize
;
306 /* Figure out how many buffer samples will be needed */
307 DataSize64
= SamplesToDo
-OutPos
;
308 DataSize64
*= increment
;
309 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
310 DataSize64
>>= FRACTIONBITS
;
311 DataSize64
+= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
313 SrcBufferSize
= (ALsizei
)mini64(DataSize64
, BUFFERSIZE
);
315 /* Figure out how many samples we can actually mix from this. */
316 DataSize64
= SrcBufferSize
;
317 DataSize64
-= MAX_POST_SAMPLES
+MAX_PRE_SAMPLES
;
318 DataSize64
<<= FRACTIONBITS
;
319 DataSize64
-= DataPosFrac
;
321 DstBufferSize
= (ALsizei
)((DataSize64
+(increment
-1)) / increment
);
322 DstBufferSize
= mini(DstBufferSize
, (SamplesToDo
-OutPos
));
324 /* Some mixers like having a multiple of 4, so try to give that unless
325 * this is the last update. */
326 if(OutPos
+DstBufferSize
< SamplesToDo
)
329 for(chan
= 0;chan
< NumChannels
;chan
++)
331 const ALfloat
*ResampledData
;
332 ALfloat
*SrcData
= Device
->SourceData
;
335 /* Load the previous samples into the source data first. */
336 memcpy(SrcData
, voice
->PrevSamples
[chan
], MAX_PRE_SAMPLES
*sizeof(ALfloat
));
337 SrcDataSize
= MAX_PRE_SAMPLES
;
339 if(Source
->SourceType
== AL_STATIC
)
341 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
342 const ALubyte
*Data
= ALBuffer
->data
;
345 /* Offset buffer data to current channel */
346 Data
+= chan
*SampleSize
;
348 /* If current pos is beyond the loop range, do not loop */
349 if(!BufferLoopItem
|| DataPosInt
>= ALBuffer
->LoopEnd
)
351 BufferLoopItem
= NULL
;
353 /* Load what's left to play from the source buffer, and
354 * clear the rest of the temp buffer */
355 DataSize
= minu(SrcBufferSize
- SrcDataSize
,
356 ALBuffer
->SampleLen
- DataPosInt
);
358 LoadSamples(&SrcData
[SrcDataSize
], &Data
[DataPosInt
* NumChannels
*SampleSize
],
359 NumChannels
, ALBuffer
->FmtType
, DataSize
);
360 SrcDataSize
+= DataSize
;
362 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
363 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
367 ALsizei LoopStart
= ALBuffer
->LoopStart
;
368 ALsizei LoopEnd
= ALBuffer
->LoopEnd
;
370 /* Load what's left of this loop iteration, then load
371 * repeats of the loop section */
372 DataSize
= minu(SrcBufferSize
- SrcDataSize
, LoopEnd
- DataPosInt
);
374 LoadSamples(&SrcData
[SrcDataSize
], &Data
[DataPosInt
* NumChannels
*SampleSize
],
375 NumChannels
, ALBuffer
->FmtType
, DataSize
);
376 SrcDataSize
+= DataSize
;
378 DataSize
= LoopEnd
-LoopStart
;
379 while(SrcBufferSize
> SrcDataSize
)
381 DataSize
= mini(SrcBufferSize
- SrcDataSize
, DataSize
);
383 LoadSamples(&SrcData
[SrcDataSize
], &Data
[LoopStart
* NumChannels
*SampleSize
],
384 NumChannels
, ALBuffer
->FmtType
, DataSize
);
385 SrcDataSize
+= DataSize
;
391 /* Crawl the buffer queue to fill in the temp buffer */
392 ALbufferlistitem
*tmpiter
= BufferListItem
;
393 ALsizei pos
= DataPosInt
;
395 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
397 const ALbuffer
*ALBuffer
;
398 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
400 const ALubyte
*Data
= ALBuffer
->data
;
401 ALsizei DataSize
= ALBuffer
->SampleLen
;
403 /* Skip the data already played */
408 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
412 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
413 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
414 ALBuffer
->FmtType
, DataSize
);
415 SrcDataSize
+= DataSize
;
418 tmpiter
= ATOMIC_LOAD(&tmpiter
->next
, almemory_order_acquire
);
419 if(!tmpiter
&& BufferLoopItem
)
420 tmpiter
= BufferLoopItem
;
423 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
424 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
429 /* Store the last source samples used for next time. */
430 memcpy(voice
->PrevSamples
[chan
],
431 &SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
432 MAX_PRE_SAMPLES
*sizeof(ALfloat
)
435 /* Now resample, then filter and mix to the appropriate outputs. */
436 ResampledData
= Resample(&voice
->ResampleState
,
437 &SrcData
[MAX_PRE_SAMPLES
], DataPosFrac
, increment
,
438 Device
->ResampledData
, DstBufferSize
441 DirectParams
*parms
= &voice
->Direct
.Params
[chan
];
442 const ALfloat
*samples
;
445 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
446 ResampledData
, DstBufferSize
, parms
->FilterType
448 if(!(voice
->Flags
&VOICE_HAS_HRTF
))
451 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
452 sizeof(parms
->Gains
.Current
));
453 if(!(voice
->Flags
&VOICE_HAS_NFC
))
454 MixSamples(samples
, voice
->Direct
.Channels
, voice
->Direct
.Buffer
,
455 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
460 static void (*const NfcUpdate
[MAX_AMBI_ORDER
])(
461 NfcFilter
*,float*,const float*,const int
463 NfcFilterUpdate1
, NfcFilterUpdate2
, NfcFilterUpdate3
465 ALfloat
*nfcsamples
= Device
->NFCtrlData
;
466 ALsizei ord
, chanoffset
= 0;
469 voice
->Direct
.ChannelsPerOrder
[0], voice
->Direct
.Buffer
,
470 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
473 chanoffset
+= voice
->Direct
.ChannelsPerOrder
[0];
474 for(ord
= 1;ord
< MAX_AMBI_ORDER
+1;ord
++)
476 if(voice
->Direct
.ChannelsPerOrder
[ord
] <= 0)
478 NfcUpdate
[ord
-1](&parms
->NFCtrlFilter
[ord
-1], nfcsamples
, samples
,
480 MixSamples(nfcsamples
, voice
->Direct
.ChannelsPerOrder
[ord
],
481 voice
->Direct
.Buffer
+chanoffset
, parms
->Gains
.Current
+chanoffset
,
482 parms
->Gains
.Target
+chanoffset
, Counter
, OutPos
, DstBufferSize
484 chanoffset
+= voice
->Direct
.ChannelsPerOrder
[ord
];
490 MixHrtfParams hrtfparams
;
494 lidx
= GetChannelIdxByName(Device
->RealOut
, FrontLeft
);
495 ridx
= GetChannelIdxByName(Device
->RealOut
, FrontRight
);
496 assert(lidx
!= -1 && ridx
!= -1);
500 /* No fading, just overwrite the old HRTF params. */
501 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
503 else if(!(parms
->Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
505 /* The old HRTF params are silent, so overwrite the old
506 * coefficients with the new, and reset the old gain to
507 * 0. The future mix will then fade from silence.
509 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
510 parms
->Hrtf
.Old
.Gain
= 0.0f
;
512 else if(firstpass
&& parms
->Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
)
514 HrtfState backupstate
= parms
->Hrtf
.State
;
517 /* Fade between the coefficients over 64 samples. */
518 fademix
= mini(DstBufferSize
, 64);
520 /* The old coefficients need to fade to silence
521 * completely since they'll be replaced after this mix.
523 hrtfparams
.Coeffs
= SAFE_CONST(ALfloat2
*,parms
->Hrtf
.Old
.Coeffs
);
524 hrtfparams
.Delay
[0] = parms
->Hrtf
.Old
.Delay
[0];
525 hrtfparams
.Delay
[1] = parms
->Hrtf
.Old
.Delay
[1];
526 hrtfparams
.Gain
= parms
->Hrtf
.Old
.Gain
;
527 hrtfparams
.GainStep
= -hrtfparams
.Gain
/ (ALfloat
)fademix
;
529 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
530 samples
, voice
->Offset
, OutPos
, IrSize
, &hrtfparams
,
531 &backupstate
, fademix
534 /* The new coefficients need to fade in completely
535 * since they're replacing the old ones. To keep the
536 * gain fading consistent, interpolate between the old
537 * and new target gains given how much of the fade time
540 gain
= lerp(parms
->Hrtf
.Old
.Gain
, parms
->Hrtf
.Target
.Gain
,
541 minf(1.0f
, (ALfloat
)fademix
/Counter
));
542 hrtfparams
.Coeffs
= SAFE_CONST(ALfloat2
*,parms
->Hrtf
.Target
.Coeffs
);
543 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
544 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
545 hrtfparams
.Gain
= 0.0f
;
546 hrtfparams
.GainStep
= gain
/ (ALfloat
)fademix
;
548 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
549 samples
, voice
->Offset
, OutPos
, IrSize
, &hrtfparams
,
550 &parms
->Hrtf
.State
, fademix
552 /* Update the old parameters with the result. */
553 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
554 if(fademix
< Counter
)
555 parms
->Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
558 if(fademix
< DstBufferSize
)
560 ALsizei todo
= DstBufferSize
- fademix
;
561 ALfloat gain
= parms
->Hrtf
.Target
.Gain
;
563 /* Interpolate the target gain if the gain fading lasts
564 * longer than this mix.
566 if(Counter
> DstBufferSize
)
567 gain
= lerp(parms
->Hrtf
.Old
.Gain
, gain
,
568 (ALfloat
)todo
/(Counter
-fademix
));
570 hrtfparams
.Coeffs
= SAFE_CONST(ALfloat2
*,parms
->Hrtf
.Target
.Coeffs
);
571 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
572 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
573 hrtfparams
.Gain
= parms
->Hrtf
.Old
.Gain
;
574 hrtfparams
.GainStep
= (gain
- parms
->Hrtf
.Old
.Gain
) / (ALfloat
)todo
;
576 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
577 samples
+fademix
, voice
->Offset
+fademix
, OutPos
+fademix
, IrSize
,
578 &hrtfparams
, &parms
->Hrtf
.State
, todo
580 /* Store the interpolated gain or the final target gain
581 * depending if the fade is done.
583 if(DstBufferSize
< Counter
)
584 parms
->Hrtf
.Old
.Gain
= gain
;
586 parms
->Hrtf
.Old
.Gain
= parms
->Hrtf
.Target
.Gain
;
591 for(send
= 0;send
< Device
->NumAuxSends
;send
++)
593 SendParams
*parms
= &voice
->Send
[send
].Params
[chan
];
594 const ALfloat
*samples
;
596 if(!voice
->Send
[send
].Buffer
)
600 &parms
->LowPass
, &parms
->HighPass
, Device
->FilteredData
,
601 ResampledData
, DstBufferSize
, parms
->FilterType
605 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
606 sizeof(parms
->Gains
.Current
));
607 MixSamples(samples
, voice
->Send
[send
].Channels
, voice
->Send
[send
].Buffer
,
608 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
, DstBufferSize
612 /* Update positions */
613 DataPosFrac
+= increment
*DstBufferSize
;
614 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
615 DataPosFrac
&= FRACTIONMASK
;
617 OutPos
+= DstBufferSize
;
618 voice
->Offset
+= DstBufferSize
;
619 Counter
= maxi(DstBufferSize
, Counter
) - DstBufferSize
;
622 /* Handle looping sources */
625 const ALbuffer
*ALBuffer
;
626 ALsizei DataSize
= 0;
627 ALsizei LoopStart
= 0;
630 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
632 DataSize
= ALBuffer
->SampleLen
;
633 LoopStart
= ALBuffer
->LoopStart
;
634 LoopEnd
= ALBuffer
->LoopEnd
;
635 if(LoopEnd
> DataPosInt
)
639 if(BufferLoopItem
&& Source
->SourceType
== AL_STATIC
)
641 assert(LoopEnd
> LoopStart
);
642 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
646 if(DataSize
> DataPosInt
)
649 BufferListItem
= ATOMIC_LOAD(&BufferListItem
->next
, almemory_order_acquire
);
652 BufferListItem
= BufferLoopItem
;
662 DataPosInt
-= DataSize
;
664 } while(isplaying
&& OutPos
< SamplesToDo
);
666 voice
->Flags
|= VOICE_IS_FADING
;
668 /* Update source info */
669 ATOMIC_STORE(&voice
->position
, DataPosInt
, almemory_order_relaxed
);
670 ATOMIC_STORE(&voice
->position_fraction
, DataPosFrac
, almemory_order_relaxed
);
671 ATOMIC_STORE(&voice
->current_buffer
, BufferListItem
, almemory_order_release
);