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"
40 static __inline ALfloat
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
41 { return vals
[0]; (void)step
; (void)frac
; }
42 static __inline ALfloat
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
43 { return lerp(vals
[0], vals
[step
], frac
* (1.0f
/FRACTIONONE
)); }
44 static __inline ALfloat
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
45 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
46 frac
* (1.0f
/FRACTIONONE
)); }
49 #define LIKELY(x) __builtin_expect(!!(x), 1)
50 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
53 #define UNLIKELY(x) (x)
56 #if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_H)
59 static __inline
void ApplyCoeffs(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
60 ALfloat (*RESTRICT Coeffs
)[2],
61 ALfloat left
, ALfloat right
)
64 float32x4_t leftright4
;
66 float32x2_t leftright2
= vdup_n_f32(0.0);
67 leftright2
= vset_lane_f32(left
, leftright2
, 0);
68 leftright2
= vset_lane_f32(right
, leftright2
, 1);
69 leftright4
= vcombine_f32(leftright2
, leftright2
);
71 for(c
= 0;c
< HRIR_LENGTH
;c
+= 2)
73 const ALuint o0
= (Offset
+c
)&HRIR_MASK
;
74 const ALuint o1
= (o0
+1)&HRIR_MASK
;
75 float32x4_t vals
= vcombine_f32(vld1_f32((float32_t
*)&Values
[o0
][0]),
76 vld1_f32((float32_t
*)&Values
[o1
][0]));
77 float32x4_t coefs
= vld1q_f32((float32_t
*)&Coeffs
[c
][0]);
79 vals
= vmlaq_f32(vals
, coefs
, leftright4
);
81 vst1_f32((float32_t
*)&Values
[o0
][0], vget_low_f32(vals
));
82 vst1_f32((float32_t
*)&Values
[o1
][0], vget_high_f32(vals
));
88 static __inline
void ApplyCoeffs(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
89 ALfloat (*RESTRICT Coeffs
)[2],
90 ALfloat left
, ALfloat right
)
93 for(c
= 0;c
< HRIR_LENGTH
;c
++)
95 const ALuint off
= (Offset
+c
)&HRIR_MASK
;
96 Values
[off
][0] += Coeffs
[c
][0] * left
;
97 Values
[off
][1] += Coeffs
[c
][1] * right
;
103 #define DECL_TEMPLATE(sampler) \
104 static void MixDirect_Hrtf_##sampler(ALsource *Source, ALCdevice *Device, \
105 DirectParams *params, const ALfloat *RESTRICT data, ALuint srcfrac, \
106 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
108 const ALuint NumChannels = Source->NumChannels; \
109 const ALint *RESTRICT DelayStep = params->Hrtf.DelayStep; \
110 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
111 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
112 ALfloat (*RESTRICT CoeffStep)[2] = params->Hrtf.CoeffStep; \
120 increment = Source->Params.Step; \
122 DryBuffer = Device->DryBuffer; \
123 ClickRemoval = Device->ClickRemoval; \
124 PendingClicks = Device->PendingClicks; \
125 DryFilter = ¶ms->iirFilter; \
127 for(i = 0;i < NumChannels;i++) \
129 ALfloat (*RESTRICT TargetCoeffs)[2] = params->Hrtf.Coeffs[i]; \
130 ALuint *RESTRICT TargetDelay = params->Hrtf.Delay[i]; \
131 ALfloat *RESTRICT History = Source->Hrtf.History[i]; \
132 ALfloat (*RESTRICT Values)[2] = Source->Hrtf.Values[i]; \
133 ALint Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos; \
134 ALuint Offset = Source->Hrtf.Offset + OutPos; \
135 ALfloat Coeffs[HRIR_LENGTH][2]; \
137 ALfloat left, right; \
142 for(c = 0;c < HRIR_LENGTH;c++) \
144 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \
145 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \
148 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter) + 32768; \
149 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter) + 32768; \
151 if(LIKELY(OutPos == 0)) \
153 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
154 value = lpFilter2PC(DryFilter, i, value); \
156 History[Offset&SRC_HISTORY_MASK] = value; \
157 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
158 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
160 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \
161 Coeffs[0][0] * left; \
162 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \
163 Coeffs[0][1] * right; \
165 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \
167 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
168 value = lpFilter2P(DryFilter, i, value); \
170 History[Offset&SRC_HISTORY_MASK] = value; \
171 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
172 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
174 Delay[0] += DelayStep[0]; \
175 Delay[1] += DelayStep[1]; \
177 Values[Offset&HRIR_MASK][0] = 0.0f; \
178 Values[Offset&HRIR_MASK][1] = 0.0f; \
181 for(c = 0;c < HRIR_LENGTH;c++) \
183 const ALuint off = (Offset+c)&HRIR_MASK; \
184 Values[off][0] += Coeffs[c][0] * left; \
185 Values[off][1] += Coeffs[c][1] * right; \
186 Coeffs[c][0] += CoeffStep[c][0]; \
187 Coeffs[c][1] += CoeffStep[c][1]; \
190 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
191 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
194 pos += frac>>FRACTIONBITS; \
195 frac &= FRACTIONMASK; \
202 for(;BufferIdx < BufferSize;BufferIdx++) \
204 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
205 value = lpFilter2P(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 Values[Offset&HRIR_MASK][0] = 0.0f; \
212 Values[Offset&HRIR_MASK][1] = 0.0f; \
215 ApplyCoeffs(Offset, Values, Coeffs, left, right); \
216 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
217 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
220 pos += frac>>FRACTIONBITS; \
221 frac &= FRACTIONMASK; \
224 if(LIKELY(OutPos == SamplesToDo)) \
226 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
227 value = lpFilter2PC(DryFilter, i, value); \
229 History[Offset&SRC_HISTORY_MASK] = value; \
230 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
231 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
233 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \
234 Coeffs[0][0] * left; \
235 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \
236 Coeffs[0][1] * right; \
238 OutPos -= BufferSize; \
242 DECL_TEMPLATE(point32
)
243 DECL_TEMPLATE(lerp32
)
244 DECL_TEMPLATE(cubic32
)
249 #define DECL_TEMPLATE(sampler) \
250 static void MixDirect_##sampler(ALsource *Source, ALCdevice *Device, \
251 DirectParams *params, const ALfloat *RESTRICT data, ALuint srcfrac, \
252 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
254 const ALuint NumChannels = Source->NumChannels; \
255 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
256 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
257 ALfloat DrySend[MAXCHANNELS]; \
265 increment = Source->Params.Step; \
267 DryBuffer = Device->DryBuffer; \
268 ClickRemoval = Device->ClickRemoval; \
269 PendingClicks = Device->PendingClicks; \
270 DryFilter = ¶ms->iirFilter; \
272 for(i = 0;i < NumChannels;i++) \
274 for(c = 0;c < MAXCHANNELS;c++) \
275 DrySend[c] = params->Gains[i][c]; \
282 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
284 value = lpFilter2PC(DryFilter, i, value); \
285 for(c = 0;c < MAXCHANNELS;c++) \
286 ClickRemoval[c] -= value*DrySend[c]; \
288 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
290 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
292 value = lpFilter2P(DryFilter, i, value); \
293 for(c = 0;c < MAXCHANNELS;c++) \
294 DryBuffer[OutPos][c] += value*DrySend[c]; \
297 pos += frac>>FRACTIONBITS; \
298 frac &= FRACTIONMASK; \
301 if(OutPos == SamplesToDo) \
303 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
305 value = lpFilter2PC(DryFilter, i, value); \
306 for(c = 0;c < MAXCHANNELS;c++) \
307 PendingClicks[c] += value*DrySend[c]; \
309 OutPos -= BufferSize; \
313 DECL_TEMPLATE(point32
)
314 DECL_TEMPLATE(lerp32
)
315 DECL_TEMPLATE(cubic32
)
319 #define DECL_TEMPLATE(sampler) \
320 static void MixSend_##sampler(ALsource *Source, ALuint sendidx, \
321 SendParams *params, const ALfloat *RESTRICT data, ALuint srcfrac, \
322 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
324 const ALuint NumChannels = Source->NumChannels; \
325 ALeffectslot *Slot; \
327 ALfloat *WetBuffer; \
328 ALfloat *WetClickRemoval; \
329 ALfloat *WetPendingClicks; \
337 increment = Source->Params.Step; \
339 Slot = Source->Params.Slot[sendidx]; \
340 WetBuffer = Slot->WetBuffer; \
341 WetClickRemoval = Slot->ClickRemoval; \
342 WetPendingClicks = Slot->PendingClicks; \
343 WetFilter = ¶ms->iirFilter; \
344 WetSend = params->Gain; \
346 for(i = 0;i < NumChannels;i++) \
353 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
355 value = lpFilter2PC(WetFilter, i, value); \
356 WetClickRemoval[0] -= value * WetSend; \
358 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
360 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
362 value = lpFilter2P(WetFilter, i, value); \
363 WetBuffer[OutPos] += value * WetSend; \
366 pos += frac>>FRACTIONBITS; \
367 frac &= FRACTIONMASK; \
370 if(OutPos == SamplesToDo) \
372 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
374 value = lpFilter2PC(WetFilter, i, value); \
375 WetPendingClicks[0] += value * WetSend; \
377 OutPos -= BufferSize; \
381 DECL_TEMPLATE(point32
)
382 DECL_TEMPLATE(lerp32
)
383 DECL_TEMPLATE(cubic32
)
388 DryMixerFunc
SelectDirectMixer(enum Resampler Resampler
)
393 return MixDirect_point32
;
394 case LinearResampler
:
395 return MixDirect_lerp32
;
397 return MixDirect_cubic32
;
404 DryMixerFunc
SelectHrtfMixer(enum Resampler Resampler
)
409 return MixDirect_Hrtf_point32
;
410 case LinearResampler
:
411 return MixDirect_Hrtf_lerp32
;
413 return MixDirect_Hrtf_cubic32
;
420 WetMixerFunc
SelectSendMixer(enum Resampler Resampler
)
425 return MixSend_point32
;
426 case LinearResampler
:
427 return MixSend_lerp32
;
429 return MixSend_cubic32
;
437 static __inline ALfloat
Sample_ALbyte(ALbyte val
)
438 { return val
* (1.0f
/127.0f
); }
440 static __inline ALfloat
Sample_ALshort(ALshort val
)
441 { return val
* (1.0f
/32767.0f
); }
443 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
446 #define DECL_TEMPLATE(T) \
447 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
450 for(i = 0;i < samples;i++) \
451 dst[i] = Sample_##T(src[i]); \
454 DECL_TEMPLATE(ALbyte
)
455 DECL_TEMPLATE(ALshort
)
456 DECL_TEMPLATE(ALfloat
)
460 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
465 Load_ALbyte(dst
, src
, samples
);
468 Load_ALshort(dst
, src
, samples
);
471 Load_ALfloat(dst
, src
, samples
);
476 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
479 for(i
= 0;i
< samples
;i
++)
484 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
486 ALbufferlistitem
*BufferListItem
;
487 ALuint DataPosInt
, DataPosFrac
;
488 ALuint BuffersPlayed
;
491 enum Resampler Resampler
;
499 /* Get source info */
500 State
= Source
->state
;
501 BuffersPlayed
= Source
->BuffersPlayed
;
502 DataPosInt
= Source
->position
;
503 DataPosFrac
= Source
->position_fraction
;
504 Looping
= Source
->Looping
;
505 increment
= Source
->Params
.Step
;
506 Resampler
= Source
->Resampler
;
507 NumChannels
= Source
->NumChannels
;
508 FrameSize
= NumChannels
* Source
->SampleSize
;
510 /* Get current buffer queue item */
511 BufferListItem
= Source
->queue
;
512 for(i
= 0;i
< BuffersPlayed
;i
++)
513 BufferListItem
= BufferListItem
->next
;
517 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
518 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
519 ALfloat StackData
[STACK_DATA_SIZE
/sizeof(ALfloat
)];
520 ALfloat
*SrcData
= StackData
;
521 ALuint SrcDataSize
= 0;
524 /* Figure out how many buffer bytes will be needed */
525 DataSize64
= SamplesToDo
-OutPos
+1;
526 DataSize64
*= increment
;
527 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
528 DataSize64
>>= FRACTIONBITS
;
529 DataSize64
+= BufferPadding
+BufferPrePadding
;
530 DataSize64
*= NumChannels
;
532 BufferSize
= (ALuint
)mini64(DataSize64
, STACK_DATA_SIZE
/sizeof(ALfloat
));
533 BufferSize
/= NumChannels
;
535 if(Source
->SourceType
== AL_STATIC
)
537 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
538 const ALubyte
*Data
= ALBuffer
->data
;
542 /* If current pos is beyond the loop range, do not loop */
543 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
547 if(DataPosInt
>= BufferPrePadding
)
548 pos
= DataPosInt
- BufferPrePadding
;
551 DataSize
= BufferPrePadding
- DataPosInt
;
552 DataSize
= minu(BufferSize
, DataSize
);
554 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
555 DataSize
*NumChannels
);
556 SrcDataSize
+= DataSize
;
557 BufferSize
-= DataSize
;
562 /* Copy what's left to play in the source buffer, and clear the
563 * rest of the temp buffer */
564 DataSize
= ALBuffer
->SampleLen
- pos
;
565 DataSize
= minu(BufferSize
, DataSize
);
567 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
568 ALBuffer
->FmtType
, DataSize
*NumChannels
);
569 SrcDataSize
+= DataSize
;
570 BufferSize
-= DataSize
;
572 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
573 BufferSize
*NumChannels
);
574 SrcDataSize
+= BufferSize
;
575 BufferSize
-= BufferSize
;
579 ALuint LoopStart
= ALBuffer
->LoopStart
;
580 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
582 if(DataPosInt
>= LoopStart
)
584 pos
= DataPosInt
-LoopStart
;
585 while(pos
< BufferPrePadding
)
586 pos
+= LoopEnd
-LoopStart
;
587 pos
-= BufferPrePadding
;
590 else if(DataPosInt
>= BufferPrePadding
)
591 pos
= DataPosInt
- BufferPrePadding
;
594 DataSize
= BufferPrePadding
- DataPosInt
;
595 DataSize
= minu(BufferSize
, DataSize
);
597 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
598 SrcDataSize
+= DataSize
;
599 BufferSize
-= DataSize
;
604 /* Copy what's left of this loop iteration, then copy repeats
605 * of the loop section */
606 DataSize
= LoopEnd
- pos
;
607 DataSize
= minu(BufferSize
, DataSize
);
609 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
610 ALBuffer
->FmtType
, DataSize
*NumChannels
);
611 SrcDataSize
+= DataSize
;
612 BufferSize
-= DataSize
;
614 DataSize
= LoopEnd
-LoopStart
;
615 while(BufferSize
> 0)
617 DataSize
= minu(BufferSize
, DataSize
);
619 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
620 ALBuffer
->FmtType
, DataSize
*NumChannels
);
621 SrcDataSize
+= DataSize
;
622 BufferSize
-= DataSize
;
628 /* Crawl the buffer queue to fill in the temp buffer */
629 ALbufferlistitem
*tmpiter
= BufferListItem
;
632 if(DataPosInt
>= BufferPrePadding
)
633 pos
= DataPosInt
- BufferPrePadding
;
636 pos
= BufferPrePadding
- DataPosInt
;
639 if(!tmpiter
->prev
&& !Looping
)
641 ALuint DataSize
= minu(BufferSize
, pos
);
643 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
644 SrcDataSize
+= DataSize
;
645 BufferSize
-= DataSize
;
652 tmpiter
= tmpiter
->prev
;
656 tmpiter
= tmpiter
->next
;
661 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
663 pos
= tmpiter
->buffer
->SampleLen
- pos
;
666 pos
-= tmpiter
->buffer
->SampleLen
;
671 while(tmpiter
&& BufferSize
> 0)
673 const ALbuffer
*ALBuffer
;
674 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
676 const ALubyte
*Data
= ALBuffer
->data
;
677 ALuint DataSize
= ALBuffer
->SampleLen
;
679 /* Skip the data already played */
684 Data
+= pos
*FrameSize
;
688 DataSize
= minu(BufferSize
, DataSize
);
689 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
690 ALBuffer
->FmtType
, DataSize
*NumChannels
);
691 SrcDataSize
+= DataSize
;
692 BufferSize
-= DataSize
;
695 tmpiter
= tmpiter
->next
;
696 if(!tmpiter
&& Looping
)
697 tmpiter
= Source
->queue
;
700 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
701 SrcDataSize
+= BufferSize
;
702 BufferSize
-= BufferSize
;
707 /* Figure out how many samples we can mix. */
708 DataSize64
= SrcDataSize
;
709 DataSize64
-= BufferPadding
+BufferPrePadding
;
710 DataSize64
<<= FRACTIONBITS
;
711 DataSize64
-= increment
;
712 DataSize64
-= DataPosFrac
;
714 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
715 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
717 SrcData
+= BufferPrePadding
*NumChannels
;
718 Source
->Params
.DryMix(Source
, Device
, &Source
->Params
.Direct
,
719 SrcData
, DataPosFrac
,
720 OutPos
, SamplesToDo
, BufferSize
);
721 for(i
= 0;i
< Device
->NumAuxSends
;i
++)
723 if(!Source
->Params
.Slot
[i
])
725 Source
->Params
.WetMix(Source
, i
, &Source
->Params
.Send
[i
],
726 SrcData
, DataPosFrac
,
727 OutPos
, SamplesToDo
, BufferSize
);
729 for(i
= 0;i
< BufferSize
;i
++)
731 DataPosFrac
+= increment
;
732 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
733 DataPosFrac
&= FRACTIONMASK
;
737 /* Handle looping sources */
740 const ALbuffer
*ALBuffer
;
742 ALuint LoopStart
= 0;
745 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
747 DataSize
= ALBuffer
->SampleLen
;
748 LoopStart
= ALBuffer
->LoopStart
;
749 LoopEnd
= ALBuffer
->LoopEnd
;
750 if(LoopEnd
> DataPosInt
)
754 if(Looping
&& Source
->SourceType
== AL_STATIC
)
756 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
760 if(DataSize
> DataPosInt
)
763 if(BufferListItem
->next
)
765 BufferListItem
= BufferListItem
->next
;
770 BufferListItem
= Source
->queue
;
776 BufferListItem
= Source
->queue
;
777 BuffersPlayed
= Source
->BuffersInQueue
;
783 DataPosInt
-= DataSize
;
785 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
787 /* Update source info */
788 Source
->state
= State
;
789 Source
->BuffersPlayed
= BuffersPlayed
;
790 Source
->position
= DataPosInt
;
791 Source
->position_fraction
= DataPosFrac
;
792 Source
->Hrtf
.Offset
+= OutPos
;
793 if(State
== AL_PLAYING
)
795 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
796 Source
->Hrtf
.Moving
= AL_TRUE
;
800 Source
->Hrtf
.Counter
= 0;
801 Source
->Hrtf
.Moving
= AL_FALSE
;