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
);
44 static inline HrtfMixerFunc
SelectHrtfMixer(void)
47 if((CPUCapFlags
&CPU_CAP_SSE
))
51 if((CPUCapFlags
&CPU_CAP_NEON
))
58 static inline MixerFunc
SelectMixer(void)
61 if((CPUCapFlags
&CPU_CAP_SSE
))
65 if((CPUCapFlags
&CPU_CAP_NEON
))
72 static inline ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
74 if(increment
== FRACTIONONE
)
75 return Resample_copy32_C
;
79 return Resample_point32_C
;
82 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
83 return Resample_lerp32_SSE41
;
86 if((CPUCapFlags
&CPU_CAP_SSE2
))
87 return Resample_lerp32_SSE2
;
89 return Resample_lerp32_C
;
91 return Resample_cubic32_C
;
93 /* Shouldn't happen */
97 return Resample_point32_C
;
101 static inline ALfloat
Sample_ALbyte(ALbyte val
)
102 { return val
* (1.0f
/127.0f
); }
104 static inline ALfloat
Sample_ALshort(ALshort val
)
105 { return val
* (1.0f
/32767.0f
); }
107 static inline ALfloat
Sample_ALfloat(ALfloat val
)
110 #define DECL_TEMPLATE(T) \
111 static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
114 for(i = 0;i < samples;i++) \
115 dst[i] = Sample_##T(src[i*srcstep]); \
118 DECL_TEMPLATE(ALbyte
)
119 DECL_TEMPLATE(ALshort
)
120 DECL_TEMPLATE(ALfloat
)
124 static void LoadSamples(ALfloat
*dst
, const ALvoid
*src
, ALuint srcstep
, enum FmtType srctype
, ALuint samples
)
129 Load_ALbyte(dst
, src
, srcstep
, samples
);
132 Load_ALshort(dst
, src
, srcstep
, samples
);
135 Load_ALfloat(dst
, src
, srcstep
, samples
);
140 static void SilenceSamples(ALfloat
*dst
, ALuint samples
)
143 for(i
= 0;i
< samples
;i
++)
148 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
149 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
150 ALuint numsamples
, enum ActiveFilters type
)
159 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
162 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
166 for(i
= 0;i
< numsamples
;)
169 ALuint todo
= minu(64, numsamples
-i
);
171 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
172 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
181 ALvoid
MixSource(ALvoice
*voice
, ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
184 HrtfMixerFunc HrtfMix
;
185 ResamplerFunc Resample
;
186 ALbufferlistitem
*BufferListItem
;
187 ALuint DataPosInt
, DataPosFrac
;
190 enum Resampler Resampler
;
198 /* Get source info */
199 State
= Source
->state
;
200 BufferListItem
= ATOMIC_LOAD(&Source
->current_buffer
);
201 DataPosInt
= Source
->position
;
202 DataPosFrac
= Source
->position_fraction
;
203 Looping
= Source
->Looping
;
204 increment
= voice
->Step
;
205 Resampler
= (increment
==FRACTIONONE
) ? PointResampler
: Source
->Resampler
;
206 NumChannels
= Source
->NumChannels
;
207 SampleSize
= Source
->SampleSize
;
210 HrtfMix
= SelectHrtfMixer();
211 Resample
= SelectResampler(Resampler
, increment
);
215 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
216 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
217 ALuint SrcBufferSize
, DstBufferSize
;
219 /* Figure out how many buffer samples will be needed */
220 DataSize64
= SamplesToDo
-OutPos
;
221 DataSize64
*= increment
;
222 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
223 DataSize64
>>= FRACTIONBITS
;
224 DataSize64
+= BufferPadding
+BufferPrePadding
;
226 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
228 /* Figure out how many samples we can actually mix from this. */
229 DataSize64
= SrcBufferSize
;
230 DataSize64
-= BufferPadding
+BufferPrePadding
;
231 DataSize64
<<= FRACTIONBITS
;
232 DataSize64
-= DataPosFrac
;
234 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
235 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
237 /* Some mixers like having a multiple of 4, so try to give that unless
238 * this is the last update. */
239 if(OutPos
+DstBufferSize
< SamplesToDo
)
242 for(chan
= 0;chan
< NumChannels
;chan
++)
244 const ALfloat
*ResampledData
;
245 ALfloat
*SrcData
= Device
->SourceData
;
246 ALuint SrcDataSize
= 0;
248 if(Source
->SourceType
== AL_STATIC
)
250 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
251 const ALubyte
*Data
= ALBuffer
->data
;
255 /* If current pos is beyond the loop range, do not loop */
256 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
260 if(DataPosInt
>= BufferPrePadding
)
261 pos
= DataPosInt
- BufferPrePadding
;
264 DataSize
= BufferPrePadding
- DataPosInt
;
265 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
267 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
268 SrcDataSize
+= DataSize
;
273 /* Copy what's left to play in the source buffer, and clear the
274 * rest of the temp buffer */
275 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
277 LoadSamples(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
278 NumChannels
, ALBuffer
->FmtType
, DataSize
);
279 SrcDataSize
+= DataSize
;
281 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
282 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
286 ALuint LoopStart
= ALBuffer
->LoopStart
;
287 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
289 if(DataPosInt
>= LoopStart
)
291 pos
= DataPosInt
-LoopStart
;
292 while(pos
< BufferPrePadding
)
293 pos
+= LoopEnd
-LoopStart
;
294 pos
-= BufferPrePadding
;
297 else if(DataPosInt
>= BufferPrePadding
)
298 pos
= DataPosInt
- BufferPrePadding
;
301 DataSize
= BufferPrePadding
- DataPosInt
;
302 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
304 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
305 SrcDataSize
+= DataSize
;
310 /* Copy what's left of this loop iteration, then copy repeats
311 * of the loop section */
312 DataSize
= LoopEnd
- pos
;
313 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
315 LoadSamples(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
316 NumChannels
, ALBuffer
->FmtType
, DataSize
);
317 SrcDataSize
+= DataSize
;
319 DataSize
= LoopEnd
-LoopStart
;
320 while(SrcBufferSize
> SrcDataSize
)
322 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
324 LoadSamples(&SrcData
[SrcDataSize
], &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
325 NumChannels
, ALBuffer
->FmtType
, DataSize
);
326 SrcDataSize
+= DataSize
;
332 /* Crawl the buffer queue to fill in the temp buffer */
333 ALbufferlistitem
*tmpiter
= BufferListItem
;
336 if(DataPosInt
>= BufferPrePadding
)
337 pos
= DataPosInt
- BufferPrePadding
;
340 pos
= BufferPrePadding
- DataPosInt
;
343 ALbufferlistitem
*prev
;
344 if((prev
=tmpiter
->prev
) != NULL
)
349 tmpiter
= tmpiter
->next
;
353 ALuint DataSize
= minu(SrcBufferSize
- SrcDataSize
, pos
);
355 SilenceSamples(&SrcData
[SrcDataSize
], DataSize
);
356 SrcDataSize
+= DataSize
;
364 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
366 pos
= tmpiter
->buffer
->SampleLen
- pos
;
369 pos
-= tmpiter
->buffer
->SampleLen
;
374 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
376 const ALbuffer
*ALBuffer
;
377 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
379 const ALubyte
*Data
= ALBuffer
->data
;
380 ALuint DataSize
= ALBuffer
->SampleLen
;
382 /* Skip the data already played */
387 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
391 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
392 LoadSamples(&SrcData
[SrcDataSize
], Data
, NumChannels
,
393 ALBuffer
->FmtType
, DataSize
);
394 SrcDataSize
+= DataSize
;
397 tmpiter
= tmpiter
->next
;
398 if(!tmpiter
&& Looping
)
399 tmpiter
= ATOMIC_LOAD(&Source
->queue
);
402 SilenceSamples(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
403 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
408 /* Now resample, then filter and mix to the appropriate outputs. */
409 ResampledData
= Resample(
410 &SrcData
[BufferPrePadding
], DataPosFrac
, increment
,
411 Device
->ResampledData
, DstBufferSize
414 DirectParams
*parms
= &voice
->Direct
;
415 const ALfloat
*samples
;
418 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
419 Device
->FilteredData
, ResampledData
, DstBufferSize
,
420 parms
->Filters
[chan
].ActiveType
423 Mix(samples
, MaxChannels
, parms
->OutBuffer
, parms
->Mix
.Gains
[chan
],
424 parms
->Counter
, OutPos
, DstBufferSize
);
426 HrtfMix(parms
->OutBuffer
, samples
, parms
->Counter
, voice
->Offset
,
427 OutPos
, parms
->Mix
.Hrtf
.IrSize
, &parms
->Mix
.Hrtf
.Params
[chan
],
428 &parms
->Mix
.Hrtf
.State
[chan
], DstBufferSize
);
431 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
433 SendParams
*parms
= &voice
->Send
[j
];
434 const ALfloat
*samples
;
436 if(!parms
->OutBuffer
)
440 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
441 Device
->FilteredData
, ResampledData
, DstBufferSize
,
442 parms
->Filters
[chan
].ActiveType
444 Mix(samples
, 1, parms
->OutBuffer
, &parms
->Gain
,
445 parms
->Counter
, OutPos
, DstBufferSize
);
448 /* Update positions */
449 DataPosFrac
+= increment
*DstBufferSize
;
450 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
451 DataPosFrac
&= FRACTIONMASK
;
453 OutPos
+= DstBufferSize
;
454 voice
->Offset
+= DstBufferSize
;
455 voice
->Direct
.Counter
= maxu(voice
->Direct
.Counter
, DstBufferSize
) - DstBufferSize
;
456 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
457 voice
->Send
[j
].Counter
= maxu(voice
->Send
[j
].Counter
, DstBufferSize
) - DstBufferSize
;
459 /* Handle looping sources */
462 const ALbuffer
*ALBuffer
;
464 ALuint LoopStart
= 0;
467 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
469 DataSize
= ALBuffer
->SampleLen
;
470 LoopStart
= ALBuffer
->LoopStart
;
471 LoopEnd
= ALBuffer
->LoopEnd
;
472 if(LoopEnd
> DataPosInt
)
476 if(Looping
&& Source
->SourceType
== AL_STATIC
)
478 assert(LoopEnd
> LoopStart
);
479 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
483 if(DataSize
> DataPosInt
)
486 if(!(BufferListItem
=BufferListItem
->next
))
489 BufferListItem
= ATOMIC_LOAD(&Source
->queue
);
493 BufferListItem
= NULL
;
500 DataPosInt
-= DataSize
;
502 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
504 /* Update source info */
505 Source
->state
= State
;
506 ATOMIC_STORE(&Source
->current_buffer
, BufferListItem
);
507 Source
->position
= DataPosInt
;
508 Source
->position_fraction
= DataPosFrac
;