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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
39 #include "mixer_defs.h"
42 DryMixerFunc
SelectDirectMixer(enum Resampler Resampler
)
45 if((CPUCapFlags
&CPU_CAP_SSE
))
50 return MixDirect_point32_SSE
;
52 return MixDirect_lerp32_SSE
;
54 return MixDirect_cubic32_SSE
;
61 if((CPUCapFlags
&CPU_CAP_NEON
))
66 return MixDirect_point32_Neon
;
68 return MixDirect_lerp32_Neon
;
70 return MixDirect_cubic32_Neon
;
80 return MixDirect_point32_C
;
82 return MixDirect_lerp32_C
;
84 return MixDirect_cubic32_C
;
91 DryMixerFunc
SelectHrtfMixer(enum Resampler Resampler
)
94 if((CPUCapFlags
&CPU_CAP_SSE
))
99 return MixDirect_Hrtf_point32_SSE
;
100 case LinearResampler
:
101 return MixDirect_Hrtf_lerp32_SSE
;
103 return MixDirect_Hrtf_cubic32_SSE
;
110 if((CPUCapFlags
&CPU_CAP_NEON
))
115 return MixDirect_Hrtf_point32_Neon
;
116 case LinearResampler
:
117 return MixDirect_Hrtf_lerp32_Neon
;
119 return MixDirect_Hrtf_cubic32_Neon
;
129 return MixDirect_Hrtf_point32_C
;
130 case LinearResampler
:
131 return MixDirect_Hrtf_lerp32_C
;
133 return MixDirect_Hrtf_cubic32_C
;
140 WetMixerFunc
SelectSendMixer(enum Resampler Resampler
)
143 if((CPUCapFlags
&CPU_CAP_SSE
))
148 return MixSend_point32_SSE
;
149 case LinearResampler
:
150 return MixSend_lerp32_SSE
;
152 return MixSend_cubic32_SSE
;
159 if((CPUCapFlags
&CPU_CAP_NEON
))
164 return MixSend_point32_Neon
;
165 case LinearResampler
:
166 return MixSend_lerp32_Neon
;
168 return MixSend_cubic32_Neon
;
178 return MixSend_point32_C
;
179 case LinearResampler
:
180 return MixSend_lerp32_C
;
182 return MixSend_cubic32_C
;
190 static __inline ALfloat
Sample_ALbyte(ALbyte val
)
191 { return val
* (1.0f
/127.0f
); }
193 static __inline ALfloat
Sample_ALshort(ALshort val
)
194 { return val
* (1.0f
/32767.0f
); }
196 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
199 #define DECL_TEMPLATE(T) \
200 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
203 for(i = 0;i < samples;i++) \
204 dst[i] = Sample_##T(src[i]); \
207 DECL_TEMPLATE(ALbyte
)
208 DECL_TEMPLATE(ALshort
)
209 DECL_TEMPLATE(ALfloat
)
213 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
218 Load_ALbyte(dst
, src
, samples
);
221 Load_ALshort(dst
, src
, samples
);
224 Load_ALfloat(dst
, src
, samples
);
229 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
232 for(i
= 0;i
< samples
;i
++)
237 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
239 ALbufferlistitem
*BufferListItem
;
240 ALuint DataPosInt
, DataPosFrac
;
241 ALuint BuffersPlayed
;
244 enum Resampler Resampler
;
252 /* Get source info */
253 State
= Source
->state
;
254 BuffersPlayed
= Source
->BuffersPlayed
;
255 DataPosInt
= Source
->position
;
256 DataPosFrac
= Source
->position_fraction
;
257 Looping
= Source
->Looping
;
258 increment
= Source
->Params
.Step
;
259 Resampler
= Source
->Resampler
;
260 NumChannels
= Source
->NumChannels
;
261 FrameSize
= NumChannels
* Source
->SampleSize
;
263 /* Get current buffer queue item */
264 BufferListItem
= Source
->queue
;
265 for(i
= 0;i
< BuffersPlayed
;i
++)
266 BufferListItem
= BufferListItem
->next
;
270 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
271 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
272 ALfloat StackData
[STACK_DATA_SIZE
/sizeof(ALfloat
)];
273 ALfloat
*SrcData
= StackData
;
274 ALuint SrcDataSize
= 0;
277 /* Figure out how many buffer bytes will be needed */
278 DataSize64
= SamplesToDo
-OutPos
+1;
279 DataSize64
*= increment
;
280 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
281 DataSize64
>>= FRACTIONBITS
;
282 DataSize64
+= BufferPadding
+BufferPrePadding
;
283 DataSize64
*= NumChannels
;
285 BufferSize
= (ALuint
)mini64(DataSize64
, STACK_DATA_SIZE
/sizeof(ALfloat
));
286 BufferSize
/= NumChannels
;
288 if(Source
->SourceType
== AL_STATIC
)
290 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
291 const ALubyte
*Data
= ALBuffer
->data
;
295 /* If current pos is beyond the loop range, do not loop */
296 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
300 if(DataPosInt
>= BufferPrePadding
)
301 pos
= DataPosInt
- BufferPrePadding
;
304 DataSize
= BufferPrePadding
- DataPosInt
;
305 DataSize
= minu(BufferSize
, DataSize
);
307 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
308 DataSize
*NumChannels
);
309 SrcDataSize
+= DataSize
;
310 BufferSize
-= DataSize
;
315 /* Copy what's left to play in the source buffer, and clear the
316 * rest of the temp buffer */
317 DataSize
= ALBuffer
->SampleLen
- pos
;
318 DataSize
= minu(BufferSize
, DataSize
);
320 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
321 ALBuffer
->FmtType
, DataSize
*NumChannels
);
322 SrcDataSize
+= DataSize
;
323 BufferSize
-= DataSize
;
325 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
326 BufferSize
*NumChannels
);
327 SrcDataSize
+= BufferSize
;
328 BufferSize
-= BufferSize
;
332 ALuint LoopStart
= ALBuffer
->LoopStart
;
333 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
335 if(DataPosInt
>= LoopStart
)
337 pos
= DataPosInt
-LoopStart
;
338 while(pos
< BufferPrePadding
)
339 pos
+= LoopEnd
-LoopStart
;
340 pos
-= BufferPrePadding
;
343 else if(DataPosInt
>= BufferPrePadding
)
344 pos
= DataPosInt
- BufferPrePadding
;
347 DataSize
= BufferPrePadding
- DataPosInt
;
348 DataSize
= minu(BufferSize
, DataSize
);
350 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
351 SrcDataSize
+= DataSize
;
352 BufferSize
-= DataSize
;
357 /* Copy what's left of this loop iteration, then copy repeats
358 * of the loop section */
359 DataSize
= LoopEnd
- pos
;
360 DataSize
= minu(BufferSize
, DataSize
);
362 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
363 ALBuffer
->FmtType
, DataSize
*NumChannels
);
364 SrcDataSize
+= DataSize
;
365 BufferSize
-= DataSize
;
367 DataSize
= LoopEnd
-LoopStart
;
368 while(BufferSize
> 0)
370 DataSize
= minu(BufferSize
, DataSize
);
372 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
373 ALBuffer
->FmtType
, DataSize
*NumChannels
);
374 SrcDataSize
+= DataSize
;
375 BufferSize
-= DataSize
;
381 /* Crawl the buffer queue to fill in the temp buffer */
382 ALbufferlistitem
*tmpiter
= BufferListItem
;
385 if(DataPosInt
>= BufferPrePadding
)
386 pos
= DataPosInt
- BufferPrePadding
;
389 pos
= BufferPrePadding
- DataPosInt
;
392 if(!tmpiter
->prev
&& !Looping
)
394 ALuint DataSize
= minu(BufferSize
, pos
);
396 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
397 SrcDataSize
+= DataSize
;
398 BufferSize
-= DataSize
;
405 tmpiter
= tmpiter
->prev
;
409 tmpiter
= tmpiter
->next
;
414 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
416 pos
= tmpiter
->buffer
->SampleLen
- pos
;
419 pos
-= tmpiter
->buffer
->SampleLen
;
424 while(tmpiter
&& BufferSize
> 0)
426 const ALbuffer
*ALBuffer
;
427 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
429 const ALubyte
*Data
= ALBuffer
->data
;
430 ALuint DataSize
= ALBuffer
->SampleLen
;
432 /* Skip the data already played */
437 Data
+= pos
*FrameSize
;
441 DataSize
= minu(BufferSize
, DataSize
);
442 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
443 ALBuffer
->FmtType
, DataSize
*NumChannels
);
444 SrcDataSize
+= DataSize
;
445 BufferSize
-= DataSize
;
448 tmpiter
= tmpiter
->next
;
449 if(!tmpiter
&& Looping
)
450 tmpiter
= Source
->queue
;
453 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
454 SrcDataSize
+= BufferSize
;
455 BufferSize
-= BufferSize
;
460 /* Figure out how many samples we can mix. */
461 DataSize64
= SrcDataSize
;
462 DataSize64
-= BufferPadding
+BufferPrePadding
;
463 DataSize64
<<= FRACTIONBITS
;
464 DataSize64
-= increment
;
465 DataSize64
-= DataPosFrac
;
467 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
468 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
470 SrcData
+= BufferPrePadding
*NumChannels
;
471 Source
->Params
.DryMix(Source
, Device
, &Source
->Params
.Direct
,
472 SrcData
, DataPosFrac
,
473 OutPos
, SamplesToDo
, BufferSize
);
474 for(i
= 0;i
< Device
->NumAuxSends
;i
++)
476 if(!Source
->Params
.Slot
[i
])
478 Source
->Params
.WetMix(Source
, i
, &Source
->Params
.Send
[i
],
479 SrcData
, DataPosFrac
,
480 OutPos
, SamplesToDo
, BufferSize
);
482 for(i
= 0;i
< BufferSize
;i
++)
484 DataPosFrac
+= increment
;
485 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
486 DataPosFrac
&= FRACTIONMASK
;
490 /* Handle looping sources */
493 const ALbuffer
*ALBuffer
;
495 ALuint LoopStart
= 0;
498 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
500 DataSize
= ALBuffer
->SampleLen
;
501 LoopStart
= ALBuffer
->LoopStart
;
502 LoopEnd
= ALBuffer
->LoopEnd
;
503 if(LoopEnd
> DataPosInt
)
507 if(Looping
&& Source
->SourceType
== AL_STATIC
)
509 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
513 if(DataSize
> DataPosInt
)
516 if(BufferListItem
->next
)
518 BufferListItem
= BufferListItem
->next
;
523 BufferListItem
= Source
->queue
;
529 BufferListItem
= Source
->queue
;
530 BuffersPlayed
= Source
->BuffersInQueue
;
536 DataPosInt
-= DataSize
;
538 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
540 /* Update source info */
541 Source
->state
= State
;
542 Source
->BuffersPlayed
= BuffersPlayed
;
543 Source
->position
= DataPosInt
;
544 Source
->position_fraction
= DataPosFrac
;
545 Source
->Hrtf
.Offset
+= OutPos
;
546 if(State
== AL_PLAYING
)
548 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
549 Source
->Hrtf
.Moving
= AL_TRUE
;
553 Source
->Hrtf
.Counter
= 0;
554 Source
->Hrtf
.Moving
= AL_FALSE
;