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"
40 #include "mixer_defs.h"
43 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
44 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
46 extern inline void InitiatePositionArrays(ALsizei frac
, ALint increment
, ALsizei
*restrict frac_arr
, ALint
*restrict pos_arr
, ALsizei size
);
49 /* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */
50 static_assert(MAX_RESAMPLE_PADDING
>= 24, "MAX_RESAMPLE_PADDING must be at least 24!");
53 enum Resampler ResamplerDefault
= LinearResampler
;
55 MixerFunc MixSamples
= Mix_C
;
56 static HrtfMixerFunc MixHrtfSamples
= MixHrtf_C
;
57 static HrtfMixerBlendFunc MixHrtfBlendSamples
= MixHrtfBlend_C
;
59 static MixerFunc
SelectMixer(void)
62 if((CPUCapFlags
&CPU_CAP_NEON
))
66 if((CPUCapFlags
&CPU_CAP_SSE
))
72 RowMixerFunc
SelectRowMixer(void)
75 if((CPUCapFlags
&CPU_CAP_NEON
))
79 if((CPUCapFlags
&CPU_CAP_SSE
))
85 static inline HrtfMixerFunc
SelectHrtfMixer(void)
88 if((CPUCapFlags
&CPU_CAP_NEON
))
92 if((CPUCapFlags
&CPU_CAP_SSE
))
98 static inline HrtfMixerBlendFunc
SelectHrtfBlendMixer(void)
101 if((CPUCapFlags
&CPU_CAP_NEON
))
102 return MixHrtfBlend_Neon
;
105 if((CPUCapFlags
&CPU_CAP_SSE
))
106 return MixHrtfBlend_SSE
;
108 return MixHrtfBlend_C
;
111 ResamplerFunc
SelectResampler(enum Resampler resampler
)
116 return Resample_point_C
;
117 case LinearResampler
:
119 if((CPUCapFlags
&CPU_CAP_NEON
))
120 return Resample_lerp_Neon
;
123 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
124 return Resample_lerp_SSE41
;
127 if((CPUCapFlags
&CPU_CAP_SSE2
))
128 return Resample_lerp_SSE2
;
130 return Resample_lerp_C
;
132 return Resample_cubic_C
;
133 case BSinc12Resampler
:
134 case BSinc24Resampler
:
136 if((CPUCapFlags
&CPU_CAP_NEON
))
137 return Resample_bsinc_Neon
;
140 if((CPUCapFlags
&CPU_CAP_SSE
))
141 return Resample_bsinc_SSE
;
143 return Resample_bsinc_C
;
146 return Resample_point_C
;
150 void aluInitMixer(void)
154 if(ConfigValueStr(NULL
, NULL
, "resampler", &str
))
156 if(strcasecmp(str
, "point") == 0 || strcasecmp(str
, "none") == 0)
157 ResamplerDefault
= PointResampler
;
158 else if(strcasecmp(str
, "linear") == 0)
159 ResamplerDefault
= LinearResampler
;
160 else if(strcasecmp(str
, "cubic") == 0)
161 ResamplerDefault
= FIR4Resampler
;
162 else if(strcasecmp(str
, "bsinc12") == 0)
163 ResamplerDefault
= BSinc12Resampler
;
164 else if(strcasecmp(str
, "bsinc24") == 0)
165 ResamplerDefault
= BSinc24Resampler
;
166 else if(strcasecmp(str
, "bsinc") == 0)
168 WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str
);
169 ResamplerDefault
= BSinc12Resampler
;
171 else if(strcasecmp(str
, "sinc4") == 0 || strcasecmp(str
, "sinc8") == 0)
173 WARN("Resampler option \"%s\" is deprecated, using cubic\n", str
);
174 ResamplerDefault
= FIR4Resampler
;
179 long n
= strtol(str
, &end
, 0);
180 if(*end
== '\0' && (n
== PointResampler
|| n
== LinearResampler
|| n
== FIR4Resampler
))
181 ResamplerDefault
= n
;
183 WARN("Invalid resampler: %s\n", str
);
187 MixHrtfBlendSamples
= SelectHrtfBlendMixer();
188 MixHrtfSamples
= SelectHrtfMixer();
189 MixSamples
= SelectMixer();
193 static inline ALfloat
Sample_ALbyte(ALbyte val
)
194 { return val
* (1.0f
/128.0f
); }
196 static inline ALfloat
Sample_ALshort(ALshort val
)
197 { return val
* (1.0f
/32768.0f
); }
199 static inline ALfloat
Sample_ALfloat(ALfloat val
)
202 #define DECL_TEMPLATE(T) \
203 static inline void Load_##T(ALfloat *restrict dst, const T *restrict src, \
204 ALint srcstep, ALsizei samples) \
207 for(i = 0;i < samples;i++) \
208 dst[i] += Sample_##T(src[i*srcstep]); \
211 DECL_TEMPLATE(ALbyte
)
212 DECL_TEMPLATE(ALshort
)
213 DECL_TEMPLATE(ALfloat
)
217 static void LoadSamples(ALfloat
*restrict dst
, const ALvoid
*restrict src
, ALint srcstep
,
218 enum FmtType srctype
, ALsizei samples
)
223 Load_ALbyte(dst
, src
, srcstep
, samples
);
226 Load_ALshort(dst
, src
, srcstep
, samples
);
229 Load_ALfloat(dst
, src
, srcstep
, samples
);
235 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
236 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
237 ALsizei numsamples
, enum ActiveFilters type
)
243 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
244 ALfilterState_processPassthru(hpfilter
, src
, numsamples
);
248 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
249 ALfilterState_processPassthru(hpfilter
, dst
, numsamples
);
252 ALfilterState_processPassthru(lpfilter
, src
, numsamples
);
253 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
257 for(i
= 0;i
< numsamples
;)
260 ALsizei todo
= mini(256, numsamples
-i
);
262 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
263 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
272 /* This function uses these device temp buffers. */
273 #define SOURCE_DATA_BUF 0
274 #define RESAMPLED_BUF 1
275 #define FILTERED_BUF 2
276 #define NFC_DATA_BUF 3
277 ALboolean
MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALsizei SamplesToDo
)
279 ALbufferlistitem
*BufferListItem
;
280 ALbufferlistitem
*BufferLoopItem
;
281 ALsizei NumChannels
, SampleSize
;
282 ResamplerFunc Resample
;
296 /* Get source info */
297 isplaying
= true; /* Will only be called while playing. */
298 isstatic
= Source
->SourceType
== AL_STATIC
;
299 DataPosInt
= ATOMIC_LOAD(&voice
->position
, almemory_order_acquire
);
300 DataPosFrac
= ATOMIC_LOAD(&voice
->position_fraction
, almemory_order_relaxed
);
301 BufferListItem
= ATOMIC_LOAD(&voice
->current_buffer
, almemory_order_relaxed
);
302 BufferLoopItem
= ATOMIC_LOAD(&voice
->loop_buffer
, almemory_order_relaxed
);
303 NumChannels
= voice
->NumChannels
;
304 SampleSize
= voice
->SampleSize
;
305 increment
= voice
->Step
;
307 IrSize
= (Device
->HrtfHandle
? Device
->HrtfHandle
->irSize
: 0);
309 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
310 Resample_copy_C
: voice
->Resampler
);
312 Counter
= (voice
->Flags
&VOICE_IS_FADING
) ? SamplesToDo
: 0;
317 ALsizei SrcBufferSize
, DstBufferSize
;
319 /* Figure out how many buffer samples will be needed */
320 DataSize64
= SamplesToDo
-OutPos
;
321 DataSize64
*= increment
;
322 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
323 DataSize64
>>= FRACTIONBITS
;
324 DataSize64
+= MAX_RESAMPLE_PADDING
*2;
325 SrcBufferSize
= (ALsizei
)mini64(DataSize64
, BUFFERSIZE
);
327 /* Figure out how many samples we can actually mix from this. */
328 DataSize64
= SrcBufferSize
;
329 DataSize64
-= MAX_RESAMPLE_PADDING
*2;
330 DataSize64
<<= FRACTIONBITS
;
331 DataSize64
-= DataPosFrac
;
332 DstBufferSize
= (ALsizei
)mini64((DataSize64
+(increment
-1)) / increment
,
333 SamplesToDo
- OutPos
);
335 /* Some mixers like having a multiple of 4, so try to give that unless
336 * this is the last update. */
337 if(DstBufferSize
< SamplesToDo
-OutPos
)
340 /* It's impossible to have a buffer list item with no entries. */
341 assert(BufferListItem
->num_buffers
> 0);
343 for(chan
= 0;chan
< NumChannels
;chan
++)
345 const ALfloat
*ResampledData
;
346 ALfloat
*SrcData
= Device
->TempBuffer
[SOURCE_DATA_BUF
];
349 /* Load the previous samples into the source data first, and clear the rest. */
350 memcpy(SrcData
, voice
->PrevSamples
[chan
], MAX_RESAMPLE_PADDING
*sizeof(ALfloat
));
351 memset(SrcData
+MAX_RESAMPLE_PADDING
, 0, (BUFFERSIZE
-MAX_RESAMPLE_PADDING
)*
353 FilledAmt
= MAX_RESAMPLE_PADDING
;
357 /* TODO: For static sources, loop points are taken from the
358 * first buffer (should be adjusted by any buffer offset, to
359 * possibly be added later).
361 const ALbuffer
*Buffer0
= BufferListItem
->buffers
[0];
362 const ALsizei LoopStart
= Buffer0
->LoopStart
;
363 const ALsizei LoopEnd
= Buffer0
->LoopEnd
;
364 const ALsizei LoopSize
= LoopEnd
- LoopStart
;
366 /* If current pos is beyond the loop range, do not loop */
367 if(!BufferLoopItem
|| DataPosInt
>= LoopEnd
)
369 ALsizei SizeToDo
= SrcBufferSize
- FilledAmt
;
373 BufferLoopItem
= NULL
;
375 for(i
= 0;i
< BufferListItem
->num_buffers
;i
++)
377 const ALbuffer
*buffer
= BufferListItem
->buffers
[i
];
378 const ALubyte
*Data
= buffer
->data
;
381 if(DataPosInt
>= buffer
->SampleLen
)
384 /* Load what's left to play from the buffer */
385 DataSize
= mini(SizeToDo
, buffer
->SampleLen
- DataPosInt
);
386 CompLen
= maxi(CompLen
, DataSize
);
388 LoadSamples(&SrcData
[FilledAmt
],
389 &Data
[(DataPosInt
*NumChannels
+ chan
)*SampleSize
],
390 NumChannels
, buffer
->FmtType
, DataSize
393 FilledAmt
+= CompLen
;
397 ALsizei SizeToDo
= mini(SrcBufferSize
- FilledAmt
, LoopEnd
- DataPosInt
);
401 for(i
= 0;i
< BufferListItem
->num_buffers
;i
++)
403 const ALbuffer
*buffer
= BufferListItem
->buffers
[i
];
404 const ALubyte
*Data
= buffer
->data
;
407 if(DataPosInt
>= buffer
->SampleLen
)
410 /* Load what's left of this loop iteration */
411 DataSize
= mini(SizeToDo
, buffer
->SampleLen
- DataPosInt
);
412 CompLen
= maxi(CompLen
, DataSize
);
414 LoadSamples(&SrcData
[FilledAmt
],
415 &Data
[(DataPosInt
*NumChannels
+ chan
)*SampleSize
],
416 NumChannels
, buffer
->FmtType
, DataSize
419 FilledAmt
+= CompLen
;
421 while(SrcBufferSize
> FilledAmt
)
423 const ALsizei SizeToDo
= mini(SrcBufferSize
- FilledAmt
, LoopSize
);
426 for(i
= 0;i
< BufferListItem
->num_buffers
;i
++)
428 const ALbuffer
*buffer
= BufferListItem
->buffers
[i
];
429 const ALubyte
*Data
= buffer
->data
;
432 if(LoopStart
>= buffer
->SampleLen
)
435 DataSize
= mini(SizeToDo
, buffer
->SampleLen
- LoopStart
);
436 CompLen
= maxi(CompLen
, DataSize
);
438 LoadSamples(&SrcData
[FilledAmt
],
439 &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
440 NumChannels
, buffer
->FmtType
, DataSize
443 FilledAmt
+= CompLen
;
449 /* Crawl the buffer queue to fill in the temp buffer */
450 ALbufferlistitem
*tmpiter
= BufferListItem
;
451 ALsizei pos
= DataPosInt
;
453 while(tmpiter
&& SrcBufferSize
> FilledAmt
)
455 ALsizei SizeToDo
= SrcBufferSize
- FilledAmt
;
459 for(i
= 0;i
< tmpiter
->num_buffers
;i
++)
461 const ALbuffer
*ALBuffer
= tmpiter
->buffers
[i
];
462 ALsizei DataSize
= ALBuffer
? ALBuffer
->SampleLen
: 0;
463 CompLen
= maxi(CompLen
, DataSize
);
467 const ALubyte
*Data
= ALBuffer
->data
;
468 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
470 DataSize
= minu(SizeToDo
, DataSize
- pos
);
471 LoadSamples(&SrcData
[FilledAmt
], Data
, NumChannels
,
472 ALBuffer
->FmtType
, DataSize
);
479 FilledAmt
+= CompLen
- pos
;
482 if(SrcBufferSize
> FilledAmt
)
484 tmpiter
= ATOMIC_LOAD(&tmpiter
->next
, almemory_order_acquire
);
485 if(!tmpiter
) tmpiter
= BufferLoopItem
;
490 /* Store the last source samples used for next time. */
491 memcpy(voice
->PrevSamples
[chan
],
492 &SrcData
[(increment
*DstBufferSize
+ DataPosFrac
)>>FRACTIONBITS
],
493 MAX_RESAMPLE_PADDING
*sizeof(ALfloat
)
496 /* Now resample, then filter and mix to the appropriate outputs. */
497 ResampledData
= Resample(&voice
->ResampleState
,
498 &SrcData
[MAX_RESAMPLE_PADDING
], DataPosFrac
, increment
,
499 Device
->TempBuffer
[RESAMPLED_BUF
], DstBufferSize
502 DirectParams
*parms
= &voice
->Direct
.Params
[chan
];
503 const ALfloat
*samples
;
506 &parms
->LowPass
, &parms
->HighPass
, Device
->TempBuffer
[FILTERED_BUF
],
507 ResampledData
, DstBufferSize
, voice
->Direct
.FilterType
509 if(!(voice
->Flags
&VOICE_HAS_HRTF
))
512 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
513 sizeof(parms
->Gains
.Current
));
514 if(!(voice
->Flags
&VOICE_HAS_NFC
))
515 MixSamples(samples
, voice
->Direct
.Channels
, voice
->Direct
.Buffer
,
516 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
521 ALfloat
*nfcsamples
= Device
->TempBuffer
[NFC_DATA_BUF
];
522 ALsizei chanoffset
= 0;
525 voice
->Direct
.ChannelsPerOrder
[0], voice
->Direct
.Buffer
,
526 parms
->Gains
.Current
, parms
->Gains
.Target
, Counter
, OutPos
,
529 chanoffset
+= voice
->Direct
.ChannelsPerOrder
[0];
530 #define APPLY_NFC_MIX(order) \
531 if(voice->Direct.ChannelsPerOrder[order] > 0) \
533 NfcFilterUpdate##order(&parms->NFCtrlFilter[order-1], nfcsamples, \
534 samples, DstBufferSize); \
535 MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order], \
536 voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
537 parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize \
539 chanoffset += voice->Direct.ChannelsPerOrder[order]; \
549 MixHrtfParams hrtfparams
;
553 lidx
= GetChannelIdxByName(&Device
->RealOut
, FrontLeft
);
554 ridx
= GetChannelIdxByName(&Device
->RealOut
, FrontRight
);
555 assert(lidx
!= -1 && ridx
!= -1);
559 /* No fading, just overwrite the old HRTF params. */
560 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
562 else if(!(parms
->Hrtf
.Old
.Gain
> GAIN_SILENCE_THRESHOLD
))
564 /* The old HRTF params are silent, so overwrite the old
565 * coefficients with the new, and reset the old gain to
566 * 0. The future mix will then fade from silence.
568 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
569 parms
->Hrtf
.Old
.Gain
= 0.0f
;
575 /* Fade between the coefficients over 128 samples. */
576 fademix
= mini(DstBufferSize
, 128);
578 /* The new coefficients need to fade in completely
579 * since they're replacing the old ones. To keep the
580 * gain fading consistent, interpolate between the old
581 * and new target gains given how much of the fade time
584 gain
= lerp(parms
->Hrtf
.Old
.Gain
, parms
->Hrtf
.Target
.Gain
,
585 minf(1.0f
, (ALfloat
)fademix
/Counter
));
586 hrtfparams
.Coeffs
= parms
->Hrtf
.Target
.Coeffs
;
587 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
588 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
589 hrtfparams
.Gain
= 0.0f
;
590 hrtfparams
.GainStep
= gain
/ (ALfloat
)fademix
;
593 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
594 samples
, voice
->Offset
, OutPos
, IrSize
, &parms
->Hrtf
.Old
,
595 &hrtfparams
, &parms
->Hrtf
.State
, fademix
597 /* Update the old parameters with the result. */
598 parms
->Hrtf
.Old
= parms
->Hrtf
.Target
;
599 if(fademix
< Counter
)
600 parms
->Hrtf
.Old
.Gain
= hrtfparams
.Gain
;
603 if(fademix
< DstBufferSize
)
605 ALsizei todo
= DstBufferSize
- fademix
;
606 ALfloat gain
= parms
->Hrtf
.Target
.Gain
;
608 /* Interpolate the target gain if the gain fading lasts
609 * longer than this mix.
611 if(Counter
> DstBufferSize
)
612 gain
= lerp(parms
->Hrtf
.Old
.Gain
, gain
,
613 (ALfloat
)todo
/(Counter
-fademix
));
615 hrtfparams
.Coeffs
= parms
->Hrtf
.Target
.Coeffs
;
616 hrtfparams
.Delay
[0] = parms
->Hrtf
.Target
.Delay
[0];
617 hrtfparams
.Delay
[1] = parms
->Hrtf
.Target
.Delay
[1];
618 hrtfparams
.Gain
= parms
->Hrtf
.Old
.Gain
;
619 hrtfparams
.GainStep
= (gain
- parms
->Hrtf
.Old
.Gain
) / (ALfloat
)todo
;
621 voice
->Direct
.Buffer
[lidx
], voice
->Direct
.Buffer
[ridx
],
622 samples
+fademix
, voice
->Offset
+fademix
, OutPos
+fademix
, IrSize
,
623 &hrtfparams
, &parms
->Hrtf
.State
, todo
625 /* Store the interpolated gain or the final target gain
626 * depending if the fade is done.
628 if(DstBufferSize
< Counter
)
629 parms
->Hrtf
.Old
.Gain
= gain
;
631 parms
->Hrtf
.Old
.Gain
= parms
->Hrtf
.Target
.Gain
;
636 for(send
= 0;send
< Device
->NumAuxSends
;send
++)
638 SendParams
*parms
= &voice
->Send
[send
].Params
[chan
];
639 const ALfloat
*samples
;
641 if(!voice
->Send
[send
].Buffer
)
645 &parms
->LowPass
, &parms
->HighPass
, Device
->TempBuffer
[FILTERED_BUF
],
646 ResampledData
, DstBufferSize
, voice
->Send
[send
].FilterType
650 memcpy(parms
->Gains
.Current
, parms
->Gains
.Target
,
651 sizeof(parms
->Gains
.Current
));
652 MixSamples(samples
, voice
->Send
[send
].Channels
, voice
->Send
[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
;
667 /* Handle looping source position */
668 if(isstatic
&& BufferLoopItem
)
670 const ALbuffer
*Buffer
= BufferListItem
->buffers
[0];
671 ALsizei LoopStart
= Buffer
->LoopStart
;
672 ALsizei LoopEnd
= Buffer
->LoopEnd
;
673 if(DataPosInt
>= LoopEnd
)
675 assert(LoopEnd
> LoopStart
);
676 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
681 /* Handle non-looping or buffer queue source position */
685 for(i
= 0;i
< BufferListItem
->num_buffers
;i
++)
687 const ALbuffer
*buffer
= BufferListItem
->buffers
[i
];
688 if(buffer
) CompLen
= maxi(CompLen
, buffer
->SampleLen
);
691 if(CompLen
> DataPosInt
)
694 BufferListItem
= ATOMIC_LOAD(&BufferListItem
->next
, almemory_order_acquire
);
697 BufferListItem
= BufferLoopItem
;
707 DataPosInt
-= CompLen
;
709 } while(isplaying
&& OutPos
< SamplesToDo
);
711 voice
->Flags
|= VOICE_IS_FADING
;
713 /* Update source info */
714 ATOMIC_STORE(&voice
->position
, DataPosInt
, almemory_order_relaxed
);
715 ATOMIC_STORE(&voice
->position_fraction
, DataPosFrac
, almemory_order_relaxed
);
716 ATOMIC_STORE(&voice
->current_buffer
, BufferListItem
, almemory_order_release
);