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(void)
45 if((CPUCapFlags
&CPU_CAP_SSE
))
49 if((CPUCapFlags
&CPU_CAP_NEON
))
50 return MixDirect_Neon
;
56 DryMixerFunc
SelectHrtfMixer(void)
59 if((CPUCapFlags
&CPU_CAP_SSE
))
60 return MixDirect_Hrtf_SSE
;
63 if((CPUCapFlags
&CPU_CAP_NEON
))
64 return MixDirect_Hrtf_Neon
;
67 return MixDirect_Hrtf_C
;
70 WetMixerFunc
SelectSendMixer(void)
73 if((CPUCapFlags
&CPU_CAP_SSE
))
77 if((CPUCapFlags
&CPU_CAP_NEON
))
85 static __inline ALfloat
Sample_ALbyte(ALbyte val
)
86 { return val
* (1.0f
/127.0f
); }
88 static __inline ALfloat
Sample_ALshort(ALshort val
)
89 { return val
* (1.0f
/32767.0f
); }
91 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
94 #define DECL_TEMPLATE(T) \
95 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
98 for(i = 0;i < samples;i++) \
99 dst[i] = Sample_##T(src[i]); \
102 DECL_TEMPLATE(ALbyte
)
103 DECL_TEMPLATE(ALshort
)
104 DECL_TEMPLATE(ALfloat
)
108 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
113 Load_ALbyte(dst
, src
, samples
);
116 Load_ALshort(dst
, src
, samples
);
119 Load_ALfloat(dst
, src
, samples
);
124 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
127 for(i
= 0;i
< samples
;i
++)
132 static __inline ALfloat
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
133 { return vals
[0]; (void)step
; (void)frac
; }
134 static __inline ALfloat
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
135 { return lerp(vals
[0], vals
[step
], frac
* (1.0f
/FRACTIONONE
)); }
136 static __inline ALfloat
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
137 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
138 frac
* (1.0f
/FRACTIONONE
)); }
140 #define DECL_TEMPLATE(Sampler) \
141 static void Resample_##Sampler(const ALfloat *data, ALuint frac, \
142 ALuint increment, ALuint NumChannels, ALfloat *RESTRICT OutBuffer, \
149 for(i = 0;i < BufferSize+1;i++) \
151 value = Sampler(data + pos*NumChannels, NumChannels, frac); \
152 OutBuffer[i] = value; \
155 pos += frac>>FRACTIONBITS; \
156 frac &= FRACTIONMASK; \
160 DECL_TEMPLATE(point32
)
161 DECL_TEMPLATE(lerp32
)
162 DECL_TEMPLATE(cubic32
)
166 static void Resample(enum Resampler Resampler
, const ALfloat
*data
, ALuint frac
,
167 ALuint increment
, ALuint NumChannels
,
168 ALfloat
*RESTRICT OutBuffer
, ALuint BufferSize
)
170 if(increment
== FRACTIONONE
)
176 Resample_point32(data
, frac
, increment
, NumChannels
,
177 OutBuffer
, BufferSize
);
179 case LinearResampler
:
180 Resample_lerp32(data
, frac
, increment
, NumChannels
,
181 OutBuffer
, BufferSize
);
184 Resample_cubic32(data
, frac
, increment
, NumChannels
,
185 OutBuffer
, BufferSize
);
188 /* Shouldn't happen */
194 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
196 ALbufferlistitem
*BufferListItem
;
197 ALuint DataPosInt
, DataPosFrac
;
198 ALuint BuffersPlayed
;
201 enum Resampler Resampler
;
209 /* Get source info */
210 State
= Source
->state
;
211 BuffersPlayed
= Source
->BuffersPlayed
;
212 DataPosInt
= Source
->position
;
213 DataPosFrac
= Source
->position_fraction
;
214 Looping
= Source
->Looping
;
215 increment
= Source
->Params
.Step
;
216 Resampler
= Source
->Resampler
;
217 NumChannels
= Source
->NumChannels
;
218 FrameSize
= NumChannels
* Source
->SampleSize
;
220 /* Get current buffer queue item */
221 BufferListItem
= Source
->queue
;
222 for(i
= 0;i
< BuffersPlayed
;i
++)
223 BufferListItem
= BufferListItem
->next
;
227 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
228 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
229 ALfloat StackData
[STACK_DATA_SIZE
/sizeof(ALfloat
)];
230 ALfloat
*SrcData
= StackData
;
231 ALuint SrcDataSize
= 0;
234 /* Figure out how many buffer bytes will be needed */
235 DataSize64
= SamplesToDo
-OutPos
+1;
236 DataSize64
*= increment
;
237 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
238 DataSize64
>>= FRACTIONBITS
;
239 DataSize64
+= BufferPadding
+BufferPrePadding
;
240 DataSize64
*= NumChannels
;
242 BufferSize
= (ALuint
)mini64(DataSize64
, STACK_DATA_SIZE
/sizeof(ALfloat
));
243 BufferSize
/= NumChannels
;
245 if(Source
->SourceType
== AL_STATIC
)
247 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
248 const ALubyte
*Data
= ALBuffer
->data
;
252 /* If current pos is beyond the loop range, do not loop */
253 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
257 if(DataPosInt
>= BufferPrePadding
)
258 pos
= DataPosInt
- BufferPrePadding
;
261 DataSize
= BufferPrePadding
- DataPosInt
;
262 DataSize
= minu(BufferSize
, DataSize
);
264 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
265 DataSize
*NumChannels
);
266 SrcDataSize
+= DataSize
;
267 BufferSize
-= DataSize
;
272 /* Copy what's left to play in the source buffer, and clear the
273 * rest of the temp buffer */
274 DataSize
= ALBuffer
->SampleLen
- pos
;
275 DataSize
= minu(BufferSize
, DataSize
);
277 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
278 ALBuffer
->FmtType
, DataSize
*NumChannels
);
279 SrcDataSize
+= DataSize
;
280 BufferSize
-= DataSize
;
282 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
283 BufferSize
*NumChannels
);
284 SrcDataSize
+= BufferSize
;
285 BufferSize
-= BufferSize
;
289 ALuint LoopStart
= ALBuffer
->LoopStart
;
290 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
292 if(DataPosInt
>= LoopStart
)
294 pos
= DataPosInt
-LoopStart
;
295 while(pos
< BufferPrePadding
)
296 pos
+= LoopEnd
-LoopStart
;
297 pos
-= BufferPrePadding
;
300 else if(DataPosInt
>= BufferPrePadding
)
301 pos
= DataPosInt
- BufferPrePadding
;
304 DataSize
= BufferPrePadding
- DataPosInt
;
305 DataSize
= minu(BufferSize
, DataSize
);
307 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
308 SrcDataSize
+= DataSize
;
309 BufferSize
-= DataSize
;
314 /* Copy what's left of this loop iteration, then copy repeats
315 * of the loop section */
316 DataSize
= LoopEnd
- pos
;
317 DataSize
= minu(BufferSize
, DataSize
);
319 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
320 ALBuffer
->FmtType
, DataSize
*NumChannels
);
321 SrcDataSize
+= DataSize
;
322 BufferSize
-= DataSize
;
324 DataSize
= LoopEnd
-LoopStart
;
325 while(BufferSize
> 0)
327 DataSize
= minu(BufferSize
, DataSize
);
329 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
330 ALBuffer
->FmtType
, DataSize
*NumChannels
);
331 SrcDataSize
+= DataSize
;
332 BufferSize
-= DataSize
;
338 /* Crawl the buffer queue to fill in the temp buffer */
339 ALbufferlistitem
*tmpiter
= BufferListItem
;
342 if(DataPosInt
>= BufferPrePadding
)
343 pos
= DataPosInt
- BufferPrePadding
;
346 pos
= BufferPrePadding
- DataPosInt
;
349 if(!tmpiter
->prev
&& !Looping
)
351 ALuint DataSize
= minu(BufferSize
, pos
);
353 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
354 SrcDataSize
+= DataSize
;
355 BufferSize
-= DataSize
;
362 tmpiter
= tmpiter
->prev
;
366 tmpiter
= tmpiter
->next
;
371 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
373 pos
= tmpiter
->buffer
->SampleLen
- pos
;
376 pos
-= tmpiter
->buffer
->SampleLen
;
381 while(tmpiter
&& BufferSize
> 0)
383 const ALbuffer
*ALBuffer
;
384 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
386 const ALubyte
*Data
= ALBuffer
->data
;
387 ALuint DataSize
= ALBuffer
->SampleLen
;
389 /* Skip the data already played */
394 Data
+= pos
*FrameSize
;
398 DataSize
= minu(BufferSize
, DataSize
);
399 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
400 ALBuffer
->FmtType
, DataSize
*NumChannels
);
401 SrcDataSize
+= DataSize
;
402 BufferSize
-= DataSize
;
405 tmpiter
= tmpiter
->next
;
406 if(!tmpiter
&& Looping
)
407 tmpiter
= Source
->queue
;
410 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
411 SrcDataSize
+= BufferSize
;
412 BufferSize
-= BufferSize
;
417 /* Figure out how many samples we can mix. */
418 DataSize64
= SrcDataSize
;
419 DataSize64
-= BufferPadding
+BufferPrePadding
;
420 DataSize64
<<= FRACTIONBITS
;
421 DataSize64
-= increment
;
422 DataSize64
-= DataPosFrac
;
424 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
425 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
427 SrcData
+= BufferPrePadding
*NumChannels
;
428 for(i
= 0;i
< NumChannels
;i
++)
430 ALfloat ResampledData
[BUFFERSIZE
];
432 Resample(Resampler
, SrcData
+i
, DataPosFrac
, increment
,
433 NumChannels
, ResampledData
, BufferSize
);
435 Source
->Params
.DryMix(Source
, Device
, &Source
->Params
.Direct
,
436 ResampledData
, i
, OutPos
, SamplesToDo
,
438 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
440 if(!Source
->Params
.Slot
[j
])
442 Source
->Params
.WetMix(Source
, j
, &Source
->Params
.Send
[j
],
443 ResampledData
, i
, OutPos
, SamplesToDo
,
447 for(i
= 0;i
< BufferSize
;i
++)
449 DataPosFrac
+= increment
;
450 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
451 DataPosFrac
&= FRACTIONMASK
;
455 /* Handle looping sources */
458 const ALbuffer
*ALBuffer
;
460 ALuint LoopStart
= 0;
463 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
465 DataSize
= ALBuffer
->SampleLen
;
466 LoopStart
= ALBuffer
->LoopStart
;
467 LoopEnd
= ALBuffer
->LoopEnd
;
468 if(LoopEnd
> DataPosInt
)
472 if(Looping
&& Source
->SourceType
== AL_STATIC
)
474 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
478 if(DataSize
> DataPosInt
)
481 if(BufferListItem
->next
)
483 BufferListItem
= BufferListItem
->next
;
488 BufferListItem
= Source
->queue
;
494 BufferListItem
= Source
->queue
;
495 BuffersPlayed
= Source
->BuffersInQueue
;
501 DataPosInt
-= DataSize
;
503 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
505 /* Update source info */
506 Source
->state
= State
;
507 Source
->BuffersPlayed
= BuffersPlayed
;
508 Source
->position
= DataPosInt
;
509 Source
->position_fraction
= DataPosFrac
;
510 Source
->Hrtf
.Offset
+= OutPos
;
511 if(State
== AL_PLAYING
)
513 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
514 Source
->Hrtf
.Moving
= AL_TRUE
;
518 Source
->Hrtf
.Counter
= 0;
519 Source
->Hrtf
.Moving
= AL_FALSE
;