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(T, sampler) \
104 static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
105 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
106 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
108 const ALuint NumChannels = Source->NumChannels; \
109 const T *RESTRICT data = srcdata; \
110 const ALint *RESTRICT DelayStep = Source->Params.HrtfDelayStep; \
111 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
112 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
113 ALfloat (*RESTRICT CoeffStep)[2] = Source->Params.HrtfCoeffStep; \
121 increment = Source->Params.Step; \
123 DryBuffer = Device->DryBuffer; \
124 ClickRemoval = Device->ClickRemoval; \
125 PendingClicks = Device->PendingClicks; \
126 DryFilter = &Source->Params.iirFilter; \
129 frac = *DataPosFrac; \
131 for(i = 0;i < NumChannels;i++) \
133 ALfloat (*RESTRICT TargetCoeffs)[2] = Source->Params.HrtfCoeffs[i]; \
134 ALuint *RESTRICT TargetDelay = Source->Params.HrtfDelay[i]; \
135 ALfloat *RESTRICT History = Source->HrtfHistory[i]; \
136 ALfloat (*RESTRICT Values)[2] = Source->HrtfValues[i]; \
137 ALint Counter = maxu(Source->HrtfCounter, OutPos) - OutPos; \
138 ALuint Offset = Source->HrtfOffset + OutPos; \
139 ALfloat Coeffs[HRIR_LENGTH][2]; \
141 ALfloat left, right; \
144 frac = *DataPosFrac; \
146 for(c = 0;c < HRIR_LENGTH;c++) \
148 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \
149 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \
152 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter) + 32768; \
153 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter) + 32768; \
155 if(LIKELY(OutPos == 0)) \
157 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
158 value = lpFilter2PC(DryFilter, i, value); \
160 History[Offset&SRC_HISTORY_MASK] = value; \
161 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
162 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
164 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \
165 Coeffs[0][0] * left; \
166 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \
167 Coeffs[0][1] * right; \
169 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \
171 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
172 value = lpFilter2P(DryFilter, i, value); \
174 History[Offset&SRC_HISTORY_MASK] = value; \
175 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
176 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
178 Delay[0] += DelayStep[0]; \
179 Delay[1] += DelayStep[1]; \
181 Values[Offset&HRIR_MASK][0] = 0.0f; \
182 Values[Offset&HRIR_MASK][1] = 0.0f; \
185 for(c = 0;c < HRIR_LENGTH;c++) \
187 const ALuint off = (Offset+c)&HRIR_MASK; \
188 Values[off][0] += Coeffs[c][0] * left; \
189 Values[off][1] += Coeffs[c][1] * right; \
190 Coeffs[c][0] += CoeffStep[c][0]; \
191 Coeffs[c][1] += CoeffStep[c][1]; \
194 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
195 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
198 pos += frac>>FRACTIONBITS; \
199 frac &= FRACTIONMASK; \
206 for(;BufferIdx < BufferSize;BufferIdx++) \
208 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
209 value = lpFilter2P(DryFilter, i, value); \
211 History[Offset&SRC_HISTORY_MASK] = value; \
212 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
213 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
215 Values[Offset&HRIR_MASK][0] = 0.0f; \
216 Values[Offset&HRIR_MASK][1] = 0.0f; \
219 ApplyCoeffs(Offset, Values, Coeffs, left, right); \
220 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
221 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
224 pos += frac>>FRACTIONBITS; \
225 frac &= FRACTIONMASK; \
228 if(LIKELY(OutPos == SamplesToDo)) \
230 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
231 value = lpFilter2PC(DryFilter, i, value); \
233 History[Offset&SRC_HISTORY_MASK] = value; \
234 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
235 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
237 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \
238 Coeffs[0][0] * left; \
239 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \
240 Coeffs[0][1] * right; \
242 OutPos -= BufferSize; \
245 for(out = 0;out < Device->NumAuxSends;out++) \
247 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
249 ALfloat *RESTRICT WetBuffer; \
250 ALfloat *RESTRICT WetClickRemoval; \
251 ALfloat *RESTRICT WetPendingClicks; \
257 WetBuffer = Slot->WetBuffer; \
258 WetClickRemoval = Slot->ClickRemoval; \
259 WetPendingClicks = Slot->PendingClicks; \
260 WetFilter = &Source->Params.Send[out].iirFilter; \
261 WetSend = Source->Params.Send[out].WetGain; \
263 for(i = 0;i < NumChannels;i++) \
266 frac = *DataPosFrac; \
268 if(LIKELY(OutPos == 0)) \
270 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
271 value = lpFilter1PC(WetFilter, i, value); \
273 WetClickRemoval[0] -= value * WetSend; \
275 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
277 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
278 value = lpFilter1P(WetFilter, i, value); \
280 WetBuffer[OutPos] += value * WetSend; \
283 pos += frac>>FRACTIONBITS; \
284 frac &= FRACTIONMASK; \
287 if(LIKELY(OutPos == SamplesToDo)) \
289 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
290 value = lpFilter1PC(WetFilter, i, value); \
292 WetPendingClicks[0] += value * WetSend; \
294 OutPos -= BufferSize; \
297 *DataPosInt += pos; \
298 *DataPosFrac = frac; \
301 DECL_TEMPLATE(ALfloat
, point32
)
302 DECL_TEMPLATE(ALfloat
, lerp32
)
303 DECL_TEMPLATE(ALfloat
, cubic32
)
308 #define DECL_TEMPLATE(T, sampler) \
309 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
310 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
311 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
313 const ALuint NumChannels = Source->NumChannels; \
314 const T *RESTRICT data = srcdata; \
315 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
316 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
317 ALfloat DrySend[MAXCHANNELS]; \
325 increment = Source->Params.Step; \
327 DryBuffer = Device->DryBuffer; \
328 ClickRemoval = Device->ClickRemoval; \
329 PendingClicks = Device->PendingClicks; \
330 DryFilter = &Source->Params.iirFilter; \
333 frac = *DataPosFrac; \
335 for(i = 0;i < NumChannels;i++) \
337 for(c = 0;c < MAXCHANNELS;c++) \
338 DrySend[c] = Source->Params.DryGains[i][c]; \
341 frac = *DataPosFrac; \
345 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
347 value = lpFilter2PC(DryFilter, i, value); \
348 for(c = 0;c < MAXCHANNELS;c++) \
349 ClickRemoval[c] -= value*DrySend[c]; \
351 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
353 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
355 value = lpFilter2P(DryFilter, i, value); \
356 for(c = 0;c < MAXCHANNELS;c++) \
357 DryBuffer[OutPos][c] += value*DrySend[c]; \
360 pos += frac>>FRACTIONBITS; \
361 frac &= FRACTIONMASK; \
364 if(OutPos == SamplesToDo) \
366 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
368 value = lpFilter2PC(DryFilter, i, value); \
369 for(c = 0;c < MAXCHANNELS;c++) \
370 PendingClicks[c] += value*DrySend[c]; \
372 OutPos -= BufferSize; \
375 for(out = 0;out < Device->NumAuxSends;out++) \
377 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
379 ALfloat *WetBuffer; \
380 ALfloat *WetClickRemoval; \
381 ALfloat *WetPendingClicks; \
387 WetBuffer = Slot->WetBuffer; \
388 WetClickRemoval = Slot->ClickRemoval; \
389 WetPendingClicks = Slot->PendingClicks; \
390 WetFilter = &Source->Params.Send[out].iirFilter; \
391 WetSend = Source->Params.Send[out].WetGain; \
393 for(i = 0;i < NumChannels;i++) \
396 frac = *DataPosFrac; \
400 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
402 value = lpFilter1PC(WetFilter, i, value); \
403 WetClickRemoval[0] -= value * WetSend; \
405 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
407 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
409 value = lpFilter1P(WetFilter, i, value); \
410 WetBuffer[OutPos] += value * WetSend; \
413 pos += frac>>FRACTIONBITS; \
414 frac &= FRACTIONMASK; \
417 if(OutPos == SamplesToDo) \
419 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
421 value = lpFilter1PC(WetFilter, i, value); \
422 WetPendingClicks[0] += value * WetSend; \
424 OutPos -= BufferSize; \
427 *DataPosInt += pos; \
428 *DataPosFrac = frac; \
431 DECL_TEMPLATE(ALfloat
, point32
)
432 DECL_TEMPLATE(ALfloat
, lerp32
)
433 DECL_TEMPLATE(ALfloat
, cubic32
)
438 MixerFunc
SelectMixer(enum Resampler Resampler
)
442 case POINT_RESAMPLER
:
443 return Mix_ALfloat_point32
;
444 case LINEAR_RESAMPLER
:
445 return Mix_ALfloat_lerp32
;
446 case CUBIC_RESAMPLER
:
447 return Mix_ALfloat_cubic32
;
455 MixerFunc
SelectHrtfMixer(enum Resampler Resampler
)
459 case POINT_RESAMPLER
:
460 return Mix_Hrtf_ALfloat_point32
;
461 case LINEAR_RESAMPLER
:
462 return Mix_Hrtf_ALfloat_lerp32
;
463 case CUBIC_RESAMPLER
:
464 return Mix_Hrtf_ALfloat_cubic32
;
473 static __inline ALfloat
Sample_ALbyte(ALbyte val
)
474 { return val
* (1.0f
/127.0f
); }
476 static __inline ALfloat
Sample_ALshort(ALshort val
)
477 { return val
* (1.0f
/32767.0f
); }
479 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
482 #define DECL_TEMPLATE(T) \
483 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
486 for(i = 0;i < samples;i++) \
487 dst[i] = Sample_##T(src[i]); \
490 DECL_TEMPLATE(ALbyte
)
491 DECL_TEMPLATE(ALshort
)
492 DECL_TEMPLATE(ALfloat
)
496 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
501 Load_ALbyte(dst
, src
, samples
);
504 Load_ALshort(dst
, src
, samples
);
507 Load_ALfloat(dst
, src
, samples
);
512 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
515 for(i
= 0;i
< samples
;i
++)
520 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
522 ALbufferlistitem
*BufferListItem
;
523 ALuint DataPosInt
, DataPosFrac
;
524 ALuint BuffersPlayed
;
527 enum Resampler Resampler
;
535 /* Get source info */
536 State
= Source
->state
;
537 BuffersPlayed
= Source
->BuffersPlayed
;
538 DataPosInt
= Source
->position
;
539 DataPosFrac
= Source
->position_fraction
;
540 Looping
= Source
->bLooping
;
541 increment
= Source
->Params
.Step
;
542 Resampler
= Source
->Resampler
;
543 NumChannels
= Source
->NumChannels
;
544 FrameSize
= NumChannels
* Source
->SampleSize
;
546 /* Get current buffer queue item */
547 BufferListItem
= Source
->queue
;
548 for(i
= 0;i
< BuffersPlayed
;i
++)
549 BufferListItem
= BufferListItem
->next
;
553 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
554 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
555 ALfloat StackData
[STACK_DATA_SIZE
/sizeof(ALfloat
)];
556 ALfloat
*SrcData
= StackData
;
557 ALuint SrcDataSize
= 0;
560 /* Figure out how many buffer bytes will be needed */
561 DataSize64
= SamplesToDo
-OutPos
+1;
562 DataSize64
*= increment
;
563 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
564 DataSize64
>>= FRACTIONBITS
;
565 DataSize64
+= BufferPadding
+BufferPrePadding
;
566 DataSize64
*= NumChannels
;
568 BufferSize
= (ALuint
)mini64(DataSize64
, STACK_DATA_SIZE
/sizeof(ALfloat
));
569 BufferSize
/= NumChannels
;
571 if(Source
->lSourceType
== AL_STATIC
)
573 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
574 const ALubyte
*Data
= ALBuffer
->data
;
578 /* If current pos is beyond the loop range, do not loop */
579 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
583 if(DataPosInt
>= BufferPrePadding
)
584 pos
= DataPosInt
- BufferPrePadding
;
587 DataSize
= BufferPrePadding
- DataPosInt
;
588 DataSize
= minu(BufferSize
, DataSize
);
590 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
591 DataSize
*NumChannels
);
592 SrcDataSize
+= DataSize
;
593 BufferSize
-= DataSize
;
598 /* Copy what's left to play in the source buffer, and clear the
599 * rest of the temp buffer */
600 DataSize
= ALBuffer
->SampleLen
- pos
;
601 DataSize
= minu(BufferSize
, DataSize
);
603 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
604 ALBuffer
->FmtType
, DataSize
*NumChannels
);
605 SrcDataSize
+= DataSize
;
606 BufferSize
-= DataSize
;
608 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
609 BufferSize
*NumChannels
);
610 SrcDataSize
+= BufferSize
;
611 BufferSize
-= BufferSize
;
615 ALuint LoopStart
= ALBuffer
->LoopStart
;
616 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
618 if(DataPosInt
>= LoopStart
)
620 pos
= DataPosInt
-LoopStart
;
621 while(pos
< BufferPrePadding
)
622 pos
+= LoopEnd
-LoopStart
;
623 pos
-= BufferPrePadding
;
626 else if(DataPosInt
>= BufferPrePadding
)
627 pos
= DataPosInt
- BufferPrePadding
;
630 DataSize
= BufferPrePadding
- DataPosInt
;
631 DataSize
= minu(BufferSize
, DataSize
);
633 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
634 SrcDataSize
+= DataSize
;
635 BufferSize
-= DataSize
;
640 /* Copy what's left of this loop iteration, then copy repeats
641 * of the loop section */
642 DataSize
= LoopEnd
- pos
;
643 DataSize
= minu(BufferSize
, DataSize
);
645 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
646 ALBuffer
->FmtType
, DataSize
*NumChannels
);
647 SrcDataSize
+= DataSize
;
648 BufferSize
-= DataSize
;
650 DataSize
= LoopEnd
-LoopStart
;
651 while(BufferSize
> 0)
653 DataSize
= minu(BufferSize
, DataSize
);
655 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
656 ALBuffer
->FmtType
, DataSize
*NumChannels
);
657 SrcDataSize
+= DataSize
;
658 BufferSize
-= DataSize
;
664 /* Crawl the buffer queue to fill in the temp buffer */
665 ALbufferlistitem
*tmpiter
= BufferListItem
;
668 if(DataPosInt
>= BufferPrePadding
)
669 pos
= DataPosInt
- BufferPrePadding
;
672 pos
= BufferPrePadding
- DataPosInt
;
675 if(!tmpiter
->prev
&& !Looping
)
677 ALuint DataSize
= minu(BufferSize
, pos
);
679 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
680 SrcDataSize
+= DataSize
;
681 BufferSize
-= DataSize
;
688 tmpiter
= tmpiter
->prev
;
692 tmpiter
= tmpiter
->next
;
697 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
699 pos
= tmpiter
->buffer
->SampleLen
- pos
;
702 pos
-= tmpiter
->buffer
->SampleLen
;
707 while(tmpiter
&& BufferSize
> 0)
709 const ALbuffer
*ALBuffer
;
710 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
712 const ALubyte
*Data
= ALBuffer
->data
;
713 ALuint DataSize
= ALBuffer
->SampleLen
;
715 /* Skip the data already played */
720 Data
+= pos
*FrameSize
;
724 DataSize
= minu(BufferSize
, DataSize
);
725 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
726 ALBuffer
->FmtType
, DataSize
*NumChannels
);
727 SrcDataSize
+= DataSize
;
728 BufferSize
-= DataSize
;
731 tmpiter
= tmpiter
->next
;
732 if(!tmpiter
&& Looping
)
733 tmpiter
= Source
->queue
;
736 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
737 SrcDataSize
+= BufferSize
;
738 BufferSize
-= BufferSize
;
743 /* Figure out how many samples we can mix. */
744 DataSize64
= SrcDataSize
;
745 DataSize64
-= BufferPadding
+BufferPrePadding
;
746 DataSize64
<<= FRACTIONBITS
;
747 DataSize64
-= increment
;
748 DataSize64
-= DataPosFrac
;
750 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
751 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
753 SrcData
+= BufferPrePadding
*NumChannels
;
754 Source
->Params
.DoMix(Source
, Device
, SrcData
, &DataPosInt
, &DataPosFrac
,
755 OutPos
, SamplesToDo
, BufferSize
);
756 OutPos
+= BufferSize
;
758 /* Handle looping sources */
761 const ALbuffer
*ALBuffer
;
763 ALuint LoopStart
= 0;
766 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
768 DataSize
= ALBuffer
->SampleLen
;
769 LoopStart
= ALBuffer
->LoopStart
;
770 LoopEnd
= ALBuffer
->LoopEnd
;
771 if(LoopEnd
> DataPosInt
)
775 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
777 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
781 if(DataSize
> DataPosInt
)
784 if(BufferListItem
->next
)
786 BufferListItem
= BufferListItem
->next
;
791 BufferListItem
= Source
->queue
;
797 BufferListItem
= Source
->queue
;
798 BuffersPlayed
= Source
->BuffersInQueue
;
804 DataPosInt
-= DataSize
;
806 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
808 /* Update source info */
809 Source
->state
= State
;
810 Source
->BuffersPlayed
= BuffersPlayed
;
811 Source
->position
= DataPosInt
;
812 Source
->position_fraction
= DataPosFrac
;
813 Source
->HrtfOffset
+= OutPos
;
814 if(State
== AL_PLAYING
)
816 Source
->HrtfCounter
= maxu(Source
->HrtfCounter
, OutPos
) - OutPos
;
817 Source
->HrtfMoving
= AL_TRUE
;
821 Source
->HrtfCounter
= 0;
822 Source
->HrtfMoving
= AL_FALSE
;