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 extern inline void InitiatePositionArrays(ALuint frac
, ALuint increment
, ALuint
*frac_arr
, ALuint
*pos_arr
, ALuint size
);
43 alignas(16) ALfloat CubicLUT
[FRACTIONONE
][4];
46 void aluInitResamplers(void)
49 for(i
= 0;i
< FRACTIONONE
;i
++)
51 ALfloat mu
= (ALfloat
)i
/ FRACTIONONE
;
52 ALfloat mu2
= mu
*mu
, mu3
= mu
*mu
*mu
;
53 CubicLUT
[i
][0] = -0.5f
*mu3
+ mu2
+ -0.5f
*mu
;
54 CubicLUT
[i
][1] = 1.5f
*mu3
+ -2.5f
*mu2
+ 1.0f
;
55 CubicLUT
[i
][2] = -1.5f
*mu3
+ 2.0f
*mu2
+ 0.5f
*mu
;
56 CubicLUT
[i
][3] = 0.5f
*mu3
+ -0.5f
*mu2
;
61 static inline HrtfMixerFunc
SelectHrtfMixer(void)
64 if((CPUCapFlags
&CPU_CAP_SSE
))
68 if((CPUCapFlags
&CPU_CAP_NEON
))
75 static inline MixerFunc
SelectMixer(void)
78 if((CPUCapFlags
&CPU_CAP_SSE
))
82 if((CPUCapFlags
&CPU_CAP_NEON
))
89 static inline ResamplerFunc
SelectResampler(enum Resampler resampler
)
94 return Resample_point32_C
;
97 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
98 return Resample_lerp32_SSE41
;
101 if((CPUCapFlags
&CPU_CAP_SSE2
))
102 return Resample_lerp32_SSE2
;
104 return Resample_lerp32_C
;
107 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
108 return Resample_cubic32_SSE41
;
111 if((CPUCapFlags
&CPU_CAP_SSE2
))
112 return Resample_cubic32_SSE2
;
114 return Resample_cubic32_C
;
116 /* Shouldn't happen */
120 return Resample_point32_C
;
124 static inline ALfloat
Sample_ALbyte(ALbyte val
)
125 { return val
* (1.0f
/127.0f
); }
127 static inline ALfloat
Sample_ALshort(ALshort val
)
128 { return val
* (1.0f
/32767.0f
); }
130 static inline ALfloat
Sample_ALfloat(ALfloat val
)
133 #define DECL_TEMPLATE(T) \
134 static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
137 for(i = 0;i < samples;i++) \
138 dst[i] = Sample_##T(src[i*srcstep]); \
141 DECL_TEMPLATE(ALbyte
)
142 DECL_TEMPLATE(ALshort
)
143 DECL_TEMPLATE(ALfloat
)
147 static void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALuint srcstep
, enum FmtType srctype
, ALuint samples
)
152 Load_ALbyte(dst
, src
, srcstep
, samples
);
155 Load_ALshort(dst
, src
, srcstep
, samples
);
158 Load_ALfloat(dst
, src
, srcstep
, samples
);
163 static inline void SilenceSamples(ALfloat
*dst
, ALuint samples
)
166 for(i
= 0;i
< samples
;i
++)
171 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
172 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
173 ALuint numsamples
, enum ActiveFilters type
)
182 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
185 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
189 for(i
= 0;i
< numsamples
;)
192 ALuint todo
= minu(256, numsamples
-i
);
194 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
195 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
204 ALvoid
MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
207 HrtfMixerFunc HrtfMix
;
208 ResamplerFunc Resample
;
209 ALbufferlistitem
*BufferListItem
;
210 ALuint DataPosInt
, DataPosFrac
;
211 ALboolean isbformat
= AL_FALSE
;
214 enum Resampler Resampler
;
223 /* Get source info */
224 State
= Source
->state
;
225 BufferListItem
= ATOMIC_LOAD(&Source
->current_buffer
);
226 DataPosInt
= Source
->position
;
227 DataPosFrac
= Source
->position_fraction
;
228 Looping
= Source
->Looping
;
229 Resampler
= Source
->Resampler
;
230 NumChannels
= Source
->NumChannels
;
231 SampleSize
= Source
->SampleSize
;
232 increment
= voice
->Step
;
234 while(BufferListItem
)
237 if((buffer
=BufferListItem
->buffer
) != NULL
)
239 isbformat
= (buffer
->FmtChannels
== FmtBFormat2D
||
240 buffer
->FmtChannels
== FmtBFormat3D
);
243 BufferListItem
= BufferListItem
->next
;
245 assert(BufferListItem
!= NULL
);
247 IrSize
= (Device
->Hrtf
? GetHrtfIrSize(Device
->Hrtf
) : 0);
250 HrtfMix
= SelectHrtfMixer();
251 Resample
= ((increment
== FRACTIONONE
&& DataPosFrac
== 0) ?
252 Resample_copy32_C
: SelectResampler(Resampler
));
256 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
257 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
258 ALuint SrcBufferSize
, DstBufferSize
;
260 /* Figure out how many buffer samples will be needed */
261 DataSize64
= SamplesToDo
-OutPos
;
262 DataSize64
*= increment
;
263 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
264 DataSize64
>>= FRACTIONBITS
;
265 DataSize64
+= BufferPadding
+BufferPrePadding
;
267 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
269 /* Figure out how many samples we can actually mix from this. */
270 DataSize64
= SrcBufferSize
;
271 DataSize64
-= BufferPadding
+BufferPrePadding
;
272 DataSize64
<<= FRACTIONBITS
;
273 DataSize64
-= DataPosFrac
;
275 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
276 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
278 /* Some mixers like having a multiple of 4, so try to give that unless
279 * this is the last update. */
280 if(OutPos
+DstBufferSize
< SamplesToDo
)
283 for(chan
= 0;chan
< NumChannels
;chan
++)
285 const ALfloat
*ResampledData
;
286 ALfloat
*SrcData
= Device
->SourceData
;
287 ALuint SrcDataSize
= 0;
289 if(Source
->SourceType
== AL_STATIC
)
291 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
292 const ALubyte
*Data
= ALBuffer
->data
;
296 /* Offset to current channel */
297 Data
+= chan
*SampleSize
;
299 /* If current pos is beyond the loop range, do not loop */
300 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
304 if(DataPosInt
>= BufferPrePadding
)
305 pos
= DataPosInt
- BufferPrePadding
;
308 DataSize
= BufferPrePadding
- DataPosInt
;
309 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
311 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
312 SrcDataSize
+= DataSize
;
317 /* Copy what's left to play in the source buffer, and clear the
318 * rest of the temp buffer */
319 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
321 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
322 NumChannels
, ALBuffer
->FmtType
, DataSize
);
323 SrcDataSize
+= DataSize
;
325 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
326 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
330 ALuint LoopStart
= ALBuffer
->LoopStart
;
331 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
333 if(DataPosInt
>= LoopStart
)
335 pos
= DataPosInt
-LoopStart
;
336 while(pos
< BufferPrePadding
)
337 pos
+= LoopEnd
-LoopStart
;
338 pos
-= BufferPrePadding
;
341 else if(DataPosInt
>= BufferPrePadding
)
342 pos
= DataPosInt
- BufferPrePadding
;
345 DataSize
= BufferPrePadding
- DataPosInt
;
346 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
348 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
349 SrcDataSize
+= DataSize
;
354 /* Copy what's left of this loop iteration, then copy repeats
355 * of the loop section */
356 DataSize
= LoopEnd
- pos
;
357 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
359 LoadSamples(&SrcData
[SrcDataSize
], &Data
[pos
* NumChannels
*SampleSize
],
360 NumChannels
, ALBuffer
->FmtType
, DataSize
);
361 SrcDataSize
+= DataSize
;
363 DataSize
= LoopEnd
-LoopStart
;
364 while(SrcBufferSize
> SrcDataSize
)
366 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
368 LoadSamples(&SrcData
[SrcDataSize
], &Data
[LoopStart
* NumChannels
*SampleSize
],
369 NumChannels
, ALBuffer
->FmtType
, DataSize
);
370 SrcDataSize
+= DataSize
;
376 /* Crawl the buffer queue to fill in the temp buffer */
377 ALbufferlistitem
*tmpiter
= BufferListItem
;
380 if(DataPosInt
>= BufferPrePadding
)
381 pos
= DataPosInt
- BufferPrePadding
;
384 pos
= BufferPrePadding
- DataPosInt
;
387 ALbufferlistitem
*prev
;
388 if((prev
=tmpiter
->prev
) != NULL
)
393 tmpiter
= tmpiter
->next
;
397 ALuint DataSize
= minu(SrcBufferSize
- SrcDataSize
, pos
);
399 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
400 SrcDataSize
+= DataSize
;
408 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
410 pos
= tmpiter
->buffer
->SampleLen
- pos
;
413 pos
-= tmpiter
->buffer
->SampleLen
;
418 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
420 const ALbuffer
*ALBuffer
;
421 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
423 const ALubyte
*Data
= ALBuffer
->data
;
424 ALuint DataSize
= ALBuffer
->SampleLen
;
426 /* Skip the data already played */
431 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
435 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
436 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
437 ALBuffer
->FmtType
, DataSize
);
438 SrcDataSize
+= DataSize
;
441 tmpiter
= tmpiter
->next
;
442 if(!tmpiter
&& Looping
)
443 tmpiter
= ATOMIC_LOAD(&Source
->queue
);
446 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
447 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
452 /* Now resample, then filter and mix to the appropriate outputs. */
453 ResampledData
= Resample(
454 &SrcData
[BufferPrePadding
], DataPosFrac
, increment
,
455 Device
->ResampledData
, DstBufferSize
458 DirectParams
*parms
= &voice
->Direct
;
459 const ALfloat
*samples
;
462 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
463 Device
->FilteredData
, ResampledData
, DstBufferSize
,
464 parms
->Filters
[chan
].ActiveType
467 Mix(samples
, parms
->OutChannels
, parms
->OutBuffer
, parms
->Gains
[chan
],
468 parms
->Counter
, OutPos
, DstBufferSize
);
470 HrtfMix(parms
->OutBuffer
, samples
, parms
->Counter
, voice
->Offset
,
471 OutPos
, IrSize
, &parms
->Hrtf
.Params
[chan
],
472 &parms
->Hrtf
.State
[chan
], DstBufferSize
);
475 /* Only the first channel for B-Format buffers (W channel) goes to
477 if(chan
> 0 && isbformat
)
479 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
481 SendParams
*parms
= &voice
->Send
[j
];
482 const ALfloat
*samples
;
484 if(!parms
->OutBuffer
)
488 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
489 Device
->FilteredData
, ResampledData
, DstBufferSize
,
490 parms
->Filters
[chan
].ActiveType
492 Mix(samples
, 1, parms
->OutBuffer
, &parms
->Gain
,
493 parms
->Counter
, OutPos
, DstBufferSize
);
496 /* Update positions */
497 DataPosFrac
+= increment
*DstBufferSize
;
498 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
499 DataPosFrac
&= FRACTIONMASK
;
501 OutPos
+= DstBufferSize
;
502 voice
->Offset
+= DstBufferSize
;
503 voice
->Direct
.Counter
= maxu(voice
->Direct
.Counter
, DstBufferSize
) - DstBufferSize
;
504 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
505 voice
->Send
[j
].Counter
= maxu(voice
->Send
[j
].Counter
, DstBufferSize
) - DstBufferSize
;
507 /* Handle looping sources */
510 const ALbuffer
*ALBuffer
;
512 ALuint LoopStart
= 0;
515 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
517 DataSize
= ALBuffer
->SampleLen
;
518 LoopStart
= ALBuffer
->LoopStart
;
519 LoopEnd
= ALBuffer
->LoopEnd
;
520 if(LoopEnd
> DataPosInt
)
524 if(Looping
&& Source
->SourceType
== AL_STATIC
)
526 assert(LoopEnd
> LoopStart
);
527 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
531 if(DataSize
> DataPosInt
)
534 if(!(BufferListItem
=BufferListItem
->next
))
537 BufferListItem
= ATOMIC_LOAD(&Source
->queue
);
541 BufferListItem
= NULL
;
548 DataPosInt
-= DataSize
;
550 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
552 /* Update source info */
553 Source
->state
= State
;
554 ATOMIC_STORE(&Source
->current_buffer
, BufferListItem
);
555 Source
->position
= DataPosInt
;
556 Source
->position_fraction
= DataPosFrac
;