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
28 #ifdef HAVE_ARM_NEON_H
37 #include "alListener.h"
38 #include "alAuxEffectSlot.h"
43 static __inline ALfloat
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
44 { return vals
[0]; (void)step
; (void)frac
; }
45 static __inline ALfloat
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
46 { return lerp(vals
[0], vals
[step
], frac
* (1.0f
/FRACTIONONE
)); }
47 static __inline ALfloat
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
48 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
49 frac
* (1.0f
/FRACTIONONE
)); }
52 #define LIKELY(x) __builtin_expect(!!(x), 1)
53 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
56 #define UNLIKELY(x) (x)
59 static __inline
void ApplyCoeffsC(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
60 ALfloat (*RESTRICT Coeffs
)[2],
61 ALfloat left
, ALfloat right
)
64 for(c
= 0;c
< HRIR_LENGTH
;c
++)
66 const ALuint off
= (Offset
+c
)&HRIR_MASK
;
67 Values
[off
][0] += Coeffs
[c
][0] * left
;
68 Values
[off
][1] += Coeffs
[c
][1] * right
;
72 #define DECL_TEMPLATE(sampler,acc) \
73 static void MixDirect_Hrtf_##sampler##_##acc( \
74 ALsource *Source, ALCdevice *Device, DirectParams *params, \
75 const ALfloat *RESTRICT data, ALuint srcfrac, \
76 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
78 const ALuint NumChannels = Source->NumChannels; \
79 const ALint *RESTRICT DelayStep = params->Hrtf.DelayStep; \
80 ALfloat (*RESTRICT DryBuffer)[MaxChannels]; \
81 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
82 ALfloat (*RESTRICT CoeffStep)[2] = params->Hrtf.CoeffStep; \
90 increment = Source->Params.Step; \
92 DryBuffer = Device->DryBuffer; \
93 ClickRemoval = Device->ClickRemoval; \
94 PendingClicks = Device->PendingClicks; \
95 DryFilter = ¶ms->iirFilter; \
97 for(i = 0;i < NumChannels;i++) \
99 ALfloat (*RESTRICT TargetCoeffs)[2] = params->Hrtf.Coeffs[i]; \
100 ALuint *RESTRICT TargetDelay = params->Hrtf.Delay[i]; \
101 ALfloat *RESTRICT History = Source->Hrtf.History[i]; \
102 ALfloat (*RESTRICT Values)[2] = Source->Hrtf.Values[i]; \
103 ALint Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos; \
104 ALuint Offset = Source->Hrtf.Offset + OutPos; \
105 ALfloat Coeffs[HRIR_LENGTH][2]; \
107 ALfloat left, right; \
112 for(c = 0;c < HRIR_LENGTH;c++) \
114 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \
115 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \
118 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter); \
119 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter); \
121 if(LIKELY(OutPos == 0)) \
123 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
124 value = lpFilter2PC(DryFilter, i, value); \
126 History[Offset&SRC_HISTORY_MASK] = value; \
127 left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], \
128 History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], \
129 (Delay[0]&HRTFDELAY_MASK)/(ALfloat)HRTFDELAY_FRACONE); \
130 right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], \
131 History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], \
132 (Delay[1]&HRTFDELAY_MASK)/(ALfloat)HRTFDELAY_FRACONE); \
134 ClickRemoval[FrontLeft] -= Values[(Offset+1)&HRIR_MASK][0] + \
135 Coeffs[0][0] * left; \
136 ClickRemoval[FrontRight] -= Values[(Offset+1)&HRIR_MASK][1] + \
137 Coeffs[0][1] * right; \
139 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \
141 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
142 value = lpFilter2P(DryFilter, i, value); \
144 History[Offset&SRC_HISTORY_MASK] = value; \
145 left = lerp(History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], \
146 History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], \
147 (Delay[0]&HRTFDELAY_MASK)/(ALfloat)HRTFDELAY_FRACONE); \
148 right = lerp(History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], \
149 History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], \
150 (Delay[1]&HRTFDELAY_MASK)/(ALfloat)HRTFDELAY_FRACONE); \
152 Delay[0] += DelayStep[0]; \
153 Delay[1] += DelayStep[1]; \
155 Values[Offset&HRIR_MASK][0] = 0.0f; \
156 Values[Offset&HRIR_MASK][1] = 0.0f; \
159 for(c = 0;c < HRIR_LENGTH;c++) \
161 const ALuint off = (Offset+c)&HRIR_MASK; \
162 Values[off][0] += Coeffs[c][0] * left; \
163 Values[off][1] += Coeffs[c][1] * right; \
164 Coeffs[c][0] += CoeffStep[c][0]; \
165 Coeffs[c][1] += CoeffStep[c][1]; \
168 DryBuffer[OutPos][FrontLeft] += Values[Offset&HRIR_MASK][0]; \
169 DryBuffer[OutPos][FrontRight] += Values[Offset&HRIR_MASK][1]; \
172 pos += frac>>FRACTIONBITS; \
173 frac &= FRACTIONMASK; \
178 Delay[0] >>= HRTFDELAY_BITS; \
179 Delay[1] >>= HRTFDELAY_BITS; \
180 for(;BufferIdx < BufferSize;BufferIdx++) \
182 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
183 value = lpFilter2P(DryFilter, i, value); \
185 History[Offset&SRC_HISTORY_MASK] = value; \
186 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
187 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
189 Values[Offset&HRIR_MASK][0] = 0.0f; \
190 Values[Offset&HRIR_MASK][1] = 0.0f; \
193 ApplyCoeffs##acc(Offset, Values, Coeffs, left, right); \
194 DryBuffer[OutPos][FrontLeft] += Values[Offset&HRIR_MASK][0]; \
195 DryBuffer[OutPos][FrontRight] += Values[Offset&HRIR_MASK][1]; \
198 pos += frac>>FRACTIONBITS; \
199 frac &= FRACTIONMASK; \
202 if(LIKELY(OutPos == SamplesToDo)) \
204 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
205 value = lpFilter2PC(DryFilter, i, value); \
207 History[Offset&SRC_HISTORY_MASK] = value; \
208 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
209 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
211 PendingClicks[FrontLeft] += Values[(Offset+1)&HRIR_MASK][0] + \
212 Coeffs[0][0] * left; \
213 PendingClicks[FrontRight] += Values[(Offset+1)&HRIR_MASK][1] + \
214 Coeffs[0][1] * right; \
216 OutPos -= BufferSize; \
220 DECL_TEMPLATE(point32
, C
)
221 DECL_TEMPLATE(lerp32
, C
)
222 DECL_TEMPLATE(cubic32
, C
)
224 #ifdef HAVE_ARM_NEON_H
226 static __inline
void ApplyCoeffsNeon(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
227 ALfloat (*RESTRICT Coeffs
)[2],
228 ALfloat left
, ALfloat right
)
231 float32x4_t leftright4
;
233 float32x2_t leftright2
= vdup_n_f32(0.0);
234 leftright2
= vset_lane_f32(left
, leftright2
, 0);
235 leftright2
= vset_lane_f32(right
, leftright2
, 1);
236 leftright4
= vcombine_f32(leftright2
, leftright2
);
238 for(c
= 0;c
< HRIR_LENGTH
;c
+= 2)
240 const ALuint o0
= (Offset
+c
)&HRIR_MASK
;
241 const ALuint o1
= (o0
+1)&HRIR_MASK
;
242 float32x4_t vals
= vcombine_f32(vld1_f32((float32_t
*)&Values
[o0
][0]),
243 vld1_f32((float32_t
*)&Values
[o1
][0]));
244 float32x4_t coefs
= vld1q_f32((float32_t
*)&Coeffs
[c
][0]);
246 vals
= vmlaq_f32(vals
, coefs
, leftright4
);
248 vst1_f32((float32_t
*)&Values
[o0
][0], vget_low_f32(vals
));
249 vst1_f32((float32_t
*)&Values
[o1
][0], vget_high_f32(vals
));
253 DECL_TEMPLATE(point32
, Neon
)
254 DECL_TEMPLATE(lerp32
, Neon
)
255 DECL_TEMPLATE(cubic32
, Neon
)
262 #define DECL_TEMPLATE(sampler) \
263 static void MixDirect_##sampler(ALsource *Source, ALCdevice *Device, \
264 DirectParams *params, const ALfloat *RESTRICT data, ALuint srcfrac, \
265 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
267 const ALuint NumChannels = Source->NumChannels; \
268 ALfloat (*RESTRICT DryBuffer)[MaxChannels]; \
269 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
270 ALfloat DrySend[MaxChannels]; \
278 increment = Source->Params.Step; \
280 DryBuffer = Device->DryBuffer; \
281 ClickRemoval = Device->ClickRemoval; \
282 PendingClicks = Device->PendingClicks; \
283 DryFilter = ¶ms->iirFilter; \
285 for(i = 0;i < NumChannels;i++) \
287 for(c = 0;c < MaxChannels;c++) \
288 DrySend[c] = params->Gains[i][c]; \
295 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
297 value = lpFilter2PC(DryFilter, i, value); \
298 for(c = 0;c < MaxChannels;c++) \
299 ClickRemoval[c] -= value*DrySend[c]; \
301 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
303 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
305 value = lpFilter2P(DryFilter, i, value); \
306 for(c = 0;c < MaxChannels;c++) \
307 DryBuffer[OutPos][c] += value*DrySend[c]; \
310 pos += frac>>FRACTIONBITS; \
311 frac &= FRACTIONMASK; \
314 if(OutPos == SamplesToDo) \
316 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
318 value = lpFilter2PC(DryFilter, i, value); \
319 for(c = 0;c < MaxChannels;c++) \
320 PendingClicks[c] += value*DrySend[c]; \
322 OutPos -= BufferSize; \
326 DECL_TEMPLATE(point32
)
327 DECL_TEMPLATE(lerp32
)
328 DECL_TEMPLATE(cubic32
)
332 #define DECL_TEMPLATE(sampler) \
333 static void MixSend_##sampler(ALsource *Source, ALuint sendidx, \
334 SendParams *params, const ALfloat *RESTRICT data, ALuint srcfrac, \
335 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
337 const ALuint NumChannels = Source->NumChannels; \
338 ALeffectslot *Slot; \
340 ALfloat *WetBuffer; \
341 ALfloat *WetClickRemoval; \
342 ALfloat *WetPendingClicks; \
350 increment = Source->Params.Step; \
352 Slot = Source->Params.Slot[sendidx]; \
353 WetBuffer = Slot->WetBuffer; \
354 WetClickRemoval = Slot->ClickRemoval; \
355 WetPendingClicks = Slot->PendingClicks; \
356 WetFilter = ¶ms->iirFilter; \
357 WetSend = params->Gain; \
359 for(i = 0;i < NumChannels;i++) \
366 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
368 value = lpFilter2PC(WetFilter, i, value); \
369 WetClickRemoval[0] -= value * WetSend; \
371 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
373 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
375 value = lpFilter2P(WetFilter, i, value); \
376 WetBuffer[OutPos] += value * WetSend; \
379 pos += frac>>FRACTIONBITS; \
380 frac &= FRACTIONMASK; \
383 if(OutPos == SamplesToDo) \
385 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
387 value = lpFilter2PC(WetFilter, i, value); \
388 WetPendingClicks[0] += value * WetSend; \
390 OutPos -= BufferSize; \
394 DECL_TEMPLATE(point32
)
395 DECL_TEMPLATE(lerp32
)
396 DECL_TEMPLATE(cubic32
)
401 DryMixerFunc
SelectDirectMixer(enum Resampler Resampler
)
406 return MixDirect_point32
;
407 case LinearResampler
:
408 return MixDirect_lerp32
;
410 return MixDirect_cubic32
;
417 DryMixerFunc
SelectHrtfMixer(enum Resampler Resampler
)
422 #ifdef HAVE_ARM_NEON_H
423 if((CPUCapFlags
&CPU_CAP_NEON
))
424 return MixDirect_Hrtf_point32_Neon
;
426 return MixDirect_Hrtf_point32_C
;
427 case LinearResampler
:
428 #ifdef HAVE_ARM_NEON_H
429 if((CPUCapFlags
&CPU_CAP_NEON
))
430 return MixDirect_Hrtf_lerp32_Neon
;
432 return MixDirect_Hrtf_lerp32_C
;
434 #ifdef HAVE_ARM_NEON_H
435 if((CPUCapFlags
&CPU_CAP_NEON
))
436 return MixDirect_Hrtf_cubic32_Neon
;
438 return MixDirect_Hrtf_cubic32_C
;
445 WetMixerFunc
SelectSendMixer(enum Resampler Resampler
)
450 return MixSend_point32
;
451 case LinearResampler
:
452 return MixSend_lerp32
;
454 return MixSend_cubic32
;
462 static __inline ALfloat
Sample_ALbyte(ALbyte val
)
463 { return val
* (1.0f
/127.0f
); }
465 static __inline ALfloat
Sample_ALshort(ALshort val
)
466 { return val
* (1.0f
/32767.0f
); }
468 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
471 #define DECL_TEMPLATE(T) \
472 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
475 for(i = 0;i < samples;i++) \
476 dst[i] = Sample_##T(src[i]); \
479 DECL_TEMPLATE(ALbyte
)
480 DECL_TEMPLATE(ALshort
)
481 DECL_TEMPLATE(ALfloat
)
485 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
490 Load_ALbyte(dst
, src
, samples
);
493 Load_ALshort(dst
, src
, samples
);
496 Load_ALfloat(dst
, src
, samples
);
501 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
504 for(i
= 0;i
< samples
;i
++)
509 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
511 ALbufferlistitem
*BufferListItem
;
512 ALuint DataPosInt
, DataPosFrac
;
513 ALuint BuffersPlayed
;
516 enum Resampler Resampler
;
524 /* Get source info */
525 State
= Source
->state
;
526 BuffersPlayed
= Source
->BuffersPlayed
;
527 DataPosInt
= Source
->position
;
528 DataPosFrac
= Source
->position_fraction
;
529 Looping
= Source
->Looping
;
530 increment
= Source
->Params
.Step
;
531 Resampler
= Source
->Resampler
;
532 NumChannels
= Source
->NumChannels
;
533 FrameSize
= NumChannels
* Source
->SampleSize
;
535 /* Get current buffer queue item */
536 BufferListItem
= Source
->queue
;
537 for(i
= 0;i
< BuffersPlayed
;i
++)
538 BufferListItem
= BufferListItem
->next
;
542 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
543 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
544 ALfloat StackData
[STACK_DATA_SIZE
/sizeof(ALfloat
)];
545 ALfloat
*SrcData
= StackData
;
546 ALuint SrcDataSize
= 0;
549 /* Figure out how many buffer bytes will be needed */
550 DataSize64
= SamplesToDo
-OutPos
+1;
551 DataSize64
*= increment
;
552 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
553 DataSize64
>>= FRACTIONBITS
;
554 DataSize64
+= BufferPadding
+BufferPrePadding
;
555 DataSize64
*= NumChannels
;
557 BufferSize
= (ALuint
)mini64(DataSize64
, STACK_DATA_SIZE
/sizeof(ALfloat
));
558 BufferSize
/= NumChannels
;
560 if(Source
->SourceType
== AL_STATIC
)
562 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
563 const ALubyte
*Data
= ALBuffer
->data
;
567 /* If current pos is beyond the loop range, do not loop */
568 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
572 if(DataPosInt
>= BufferPrePadding
)
573 pos
= DataPosInt
- BufferPrePadding
;
576 DataSize
= BufferPrePadding
- DataPosInt
;
577 DataSize
= minu(BufferSize
, DataSize
);
579 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
580 DataSize
*NumChannels
);
581 SrcDataSize
+= DataSize
;
582 BufferSize
-= DataSize
;
587 /* Copy what's left to play in the source buffer, and clear the
588 * rest of the temp buffer */
589 DataSize
= ALBuffer
->SampleLen
- pos
;
590 DataSize
= minu(BufferSize
, DataSize
);
592 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
593 ALBuffer
->FmtType
, DataSize
*NumChannels
);
594 SrcDataSize
+= DataSize
;
595 BufferSize
-= DataSize
;
597 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
598 BufferSize
*NumChannels
);
599 SrcDataSize
+= BufferSize
;
600 BufferSize
-= BufferSize
;
604 ALuint LoopStart
= ALBuffer
->LoopStart
;
605 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
607 if(DataPosInt
>= LoopStart
)
609 pos
= DataPosInt
-LoopStart
;
610 while(pos
< BufferPrePadding
)
611 pos
+= LoopEnd
-LoopStart
;
612 pos
-= BufferPrePadding
;
615 else if(DataPosInt
>= BufferPrePadding
)
616 pos
= DataPosInt
- BufferPrePadding
;
619 DataSize
= BufferPrePadding
- DataPosInt
;
620 DataSize
= minu(BufferSize
, DataSize
);
622 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
623 SrcDataSize
+= DataSize
;
624 BufferSize
-= DataSize
;
629 /* Copy what's left of this loop iteration, then copy repeats
630 * of the loop section */
631 DataSize
= LoopEnd
- pos
;
632 DataSize
= minu(BufferSize
, DataSize
);
634 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
635 ALBuffer
->FmtType
, DataSize
*NumChannels
);
636 SrcDataSize
+= DataSize
;
637 BufferSize
-= DataSize
;
639 DataSize
= LoopEnd
-LoopStart
;
640 while(BufferSize
> 0)
642 DataSize
= minu(BufferSize
, DataSize
);
644 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
645 ALBuffer
->FmtType
, DataSize
*NumChannels
);
646 SrcDataSize
+= DataSize
;
647 BufferSize
-= DataSize
;
653 /* Crawl the buffer queue to fill in the temp buffer */
654 ALbufferlistitem
*tmpiter
= BufferListItem
;
657 if(DataPosInt
>= BufferPrePadding
)
658 pos
= DataPosInt
- BufferPrePadding
;
661 pos
= BufferPrePadding
- DataPosInt
;
664 if(!tmpiter
->prev
&& !Looping
)
666 ALuint DataSize
= minu(BufferSize
, pos
);
668 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
669 SrcDataSize
+= DataSize
;
670 BufferSize
-= DataSize
;
677 tmpiter
= tmpiter
->prev
;
681 tmpiter
= tmpiter
->next
;
686 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
688 pos
= tmpiter
->buffer
->SampleLen
- pos
;
691 pos
-= tmpiter
->buffer
->SampleLen
;
696 while(tmpiter
&& BufferSize
> 0)
698 const ALbuffer
*ALBuffer
;
699 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
701 const ALubyte
*Data
= ALBuffer
->data
;
702 ALuint DataSize
= ALBuffer
->SampleLen
;
704 /* Skip the data already played */
709 Data
+= pos
*FrameSize
;
713 DataSize
= minu(BufferSize
, DataSize
);
714 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
715 ALBuffer
->FmtType
, DataSize
*NumChannels
);
716 SrcDataSize
+= DataSize
;
717 BufferSize
-= DataSize
;
720 tmpiter
= tmpiter
->next
;
721 if(!tmpiter
&& Looping
)
722 tmpiter
= Source
->queue
;
725 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
726 SrcDataSize
+= BufferSize
;
727 BufferSize
-= BufferSize
;
732 /* Figure out how many samples we can mix. */
733 DataSize64
= SrcDataSize
;
734 DataSize64
-= BufferPadding
+BufferPrePadding
;
735 DataSize64
<<= FRACTIONBITS
;
736 DataSize64
-= increment
;
737 DataSize64
-= DataPosFrac
;
739 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
740 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
742 SrcData
+= BufferPrePadding
*NumChannels
;
743 Source
->Params
.DryMix(Source
, Device
, &Source
->Params
.Direct
,
744 SrcData
, DataPosFrac
,
745 OutPos
, SamplesToDo
, BufferSize
);
746 for(i
= 0;i
< Device
->NumAuxSends
;i
++)
748 if(!Source
->Params
.Slot
[i
])
750 Source
->Params
.WetMix(Source
, i
, &Source
->Params
.Send
[i
],
751 SrcData
, DataPosFrac
,
752 OutPos
, SamplesToDo
, BufferSize
);
754 for(i
= 0;i
< BufferSize
;i
++)
756 DataPosFrac
+= increment
;
757 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
758 DataPosFrac
&= FRACTIONMASK
;
762 /* Handle looping sources */
765 const ALbuffer
*ALBuffer
;
767 ALuint LoopStart
= 0;
770 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
772 DataSize
= ALBuffer
->SampleLen
;
773 LoopStart
= ALBuffer
->LoopStart
;
774 LoopEnd
= ALBuffer
->LoopEnd
;
775 if(LoopEnd
> DataPosInt
)
779 if(Looping
&& Source
->SourceType
== AL_STATIC
)
781 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
785 if(DataSize
> DataPosInt
)
788 if(BufferListItem
->next
)
790 BufferListItem
= BufferListItem
->next
;
795 BufferListItem
= Source
->queue
;
801 BufferListItem
= Source
->queue
;
802 BuffersPlayed
= Source
->BuffersInQueue
;
808 DataPosInt
-= DataSize
;
810 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
812 /* Update source info */
813 Source
->state
= State
;
814 Source
->BuffersPlayed
= BuffersPlayed
;
815 Source
->position
= DataPosInt
;
816 Source
->position_fraction
= DataPosFrac
;
817 Source
->Hrtf
.Offset
+= OutPos
;
818 if(State
== AL_PLAYING
)
820 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
821 Source
->Hrtf
.Moving
= AL_TRUE
;
825 Source
->Hrtf
.Counter
= 0;
826 Source
->Hrtf
.Moving
= AL_FALSE
;