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 ALdouble
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
41 { return vals
[0]; (void)step
; (void)frac
; }
42 static __inline ALdouble
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
43 { return lerp(vals
[0], vals
[step
], frac
* (1.0/FRACTIONONE
)); }
44 static __inline ALdouble
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
45 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
46 frac
* (1.0/FRACTIONONE
)); }
48 static __inline ALdouble
point16(const ALshort
*vals
, ALint step
, ALint frac
)
49 { return vals
[0] * (1.0/32767.0); (void)step
; (void)frac
; }
50 static __inline ALdouble
lerp16(const ALshort
*vals
, ALint step
, ALint frac
)
51 { return lerp(vals
[0], vals
[step
], frac
* (1.0/FRACTIONONE
)) * (1.0/32767.0); }
52 static __inline ALdouble
cubic16(const ALshort
*vals
, ALint step
, ALint frac
)
53 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
54 frac
* (1.0/FRACTIONONE
)) * (1.0/32767.0); }
56 static __inline ALdouble
point8(const ALbyte
*vals
, ALint step
, ALint frac
)
57 { return vals
[0] * (1.0/127.0); (void)step
; (void)frac
; }
58 static __inline ALdouble
lerp8(const ALbyte
*vals
, ALint step
, ALint frac
)
59 { return lerp(vals
[0], vals
[step
], frac
* (1.0/FRACTIONONE
)) * (1.0/127.0); }
60 static __inline ALdouble
cubic8(const ALbyte
*vals
, ALint step
, ALint frac
)
61 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
62 frac
* (1.0/FRACTIONONE
)) * (1.0/127.0); }
65 #define LIKELY(x) __builtin_expect(!!(x), 1)
66 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
69 #define UNLIKELY(x) (x)
72 #if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_H)
75 static __inline
void ApplyCoeffs(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
76 ALfloat (*RESTRICT Coeffs
)[2],
77 ALfloat left
, ALfloat right
)
80 float32x4_t leftright4
;
82 float32x2_t leftright2
= vdup_n_f32(0.0);
83 leftright2
= vset_lane_f32(left
, leftright2
, 0);
84 leftright2
= vset_lane_f32(right
, leftright2
, 1);
85 leftright4
= vcombine_f32(leftright2
, leftright2
);
87 for(c
= 0;c
< HRIR_LENGTH
;c
+= 2)
89 const ALuint o0
= (Offset
+c
)&HRIR_MASK
;
90 const ALuint o1
= (o0
+1)&HRIR_MASK
;
91 float32x4_t vals
= vcombine_f32(vld1_f32((float32_t
*)&Values
[o0
][0]),
92 vld1_f32((float32_t
*)&Values
[o1
][0]));
93 float32x4_t coefs
= vld1q_f32((float32_t
*)&Coeffs
[c
][0]);
95 vals
= vmlaq_f32(vals
, coefs
, leftright4
);
97 vst1_f32((float32_t
*)&Values
[o0
][0], vget_low_f32(vals
));
98 vst1_f32((float32_t
*)&Values
[o1
][0], vget_high_f32(vals
));
104 static __inline
void ApplyCoeffs(ALuint Offset
, ALfloat (*RESTRICT Values
)[2],
105 ALfloat (*RESTRICT Coeffs
)[2],
106 ALfloat left
, ALfloat right
)
109 for(c
= 0;c
< HRIR_LENGTH
;c
++)
111 const ALuint off
= (Offset
+c
)&HRIR_MASK
;
112 Values
[off
][0] += Coeffs
[c
][0] * left
;
113 Values
[off
][1] += Coeffs
[c
][1] * right
;
119 #define DECL_TEMPLATE(T, sampler) \
120 static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
121 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
122 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
124 const ALuint NumChannels = Source->NumChannels; \
125 const T *RESTRICT data = srcdata; \
126 const ALint *RESTRICT DelayStep = Source->Params.HrtfDelayStep; \
127 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
128 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
129 ALfloat (*RESTRICT CoeffStep)[2] = Source->Params.HrtfCoeffStep; \
137 increment = Source->Params.Step; \
139 DryBuffer = Device->DryBuffer; \
140 ClickRemoval = Device->ClickRemoval; \
141 PendingClicks = Device->PendingClicks; \
142 DryFilter = &Source->Params.iirFilter; \
145 frac = *DataPosFrac; \
147 for(i = 0;i < NumChannels;i++) \
149 ALfloat (*RESTRICT TargetCoeffs)[2] = Source->Params.HrtfCoeffs[i]; \
150 ALuint *RESTRICT TargetDelay = Source->Params.HrtfDelay[i]; \
151 ALfloat *RESTRICT History = Source->HrtfHistory[i]; \
152 ALfloat (*RESTRICT Values)[2] = Source->HrtfValues[i]; \
153 ALint Counter = maxu(Source->HrtfCounter, OutPos) - OutPos; \
154 ALuint Offset = Source->HrtfOffset + OutPos; \
155 ALfloat Coeffs[HRIR_LENGTH][2]; \
157 ALfloat left, right; \
160 frac = *DataPosFrac; \
162 for(c = 0;c < HRIR_LENGTH;c++) \
164 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \
165 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \
168 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter) + 32768; \
169 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter) + 32768; \
171 if(LIKELY(OutPos == 0)) \
173 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
174 value = lpFilter2PC(DryFilter, i, value); \
176 History[Offset&SRC_HISTORY_MASK] = value; \
177 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
178 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
180 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \
181 Coeffs[0][0] * left; \
182 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \
183 Coeffs[0][1] * right; \
185 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \
187 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
188 value = lpFilter2P(DryFilter, i, value); \
190 History[Offset&SRC_HISTORY_MASK] = value; \
191 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
192 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
194 Delay[0] += DelayStep[0]; \
195 Delay[1] += DelayStep[1]; \
197 Values[Offset&HRIR_MASK][0] = 0.0f; \
198 Values[Offset&HRIR_MASK][1] = 0.0f; \
201 for(c = 0;c < HRIR_LENGTH;c++) \
203 const ALuint off = (Offset+c)&HRIR_MASK; \
204 Values[off][0] += Coeffs[c][0] * left; \
205 Values[off][1] += Coeffs[c][1] * right; \
206 Coeffs[c][0] += CoeffStep[c][0]; \
207 Coeffs[c][1] += CoeffStep[c][1]; \
210 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
211 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
214 pos += frac>>FRACTIONBITS; \
215 frac &= FRACTIONMASK; \
222 for(;BufferIdx < BufferSize;BufferIdx++) \
224 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
225 value = lpFilter2P(DryFilter, i, value); \
227 History[Offset&SRC_HISTORY_MASK] = value; \
228 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
229 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
231 Values[Offset&HRIR_MASK][0] = 0.0f; \
232 Values[Offset&HRIR_MASK][1] = 0.0f; \
235 ApplyCoeffs(Offset, Values, Coeffs, left, right); \
236 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
237 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
240 pos += frac>>FRACTIONBITS; \
241 frac &= FRACTIONMASK; \
244 if(LIKELY(OutPos == SamplesToDo)) \
246 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
247 value = lpFilter2PC(DryFilter, i, value); \
249 History[Offset&SRC_HISTORY_MASK] = value; \
250 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
251 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
253 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \
254 Coeffs[0][0] * left; \
255 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \
256 Coeffs[0][1] * right; \
258 OutPos -= BufferSize; \
261 for(out = 0;out < Device->NumAuxSends;out++) \
263 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
265 ALfloat *RESTRICT WetBuffer; \
266 ALfloat *RESTRICT WetClickRemoval; \
267 ALfloat *RESTRICT WetPendingClicks; \
270 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
273 WetBuffer = Slot->WetBuffer; \
274 WetClickRemoval = Slot->ClickRemoval; \
275 WetPendingClicks = Slot->PendingClicks; \
276 WetFilter = &Source->Params.Send[out].iirFilter; \
277 WetSend = Source->Params.Send[out].WetGain; \
279 for(i = 0;i < NumChannels;i++) \
282 frac = *DataPosFrac; \
284 if(LIKELY(OutPos == 0)) \
286 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
287 value = lpFilter1PC(WetFilter, i, value); \
289 WetClickRemoval[0] -= value * WetSend; \
291 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
293 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
294 value = lpFilter1P(WetFilter, i, value); \
296 WetBuffer[OutPos] += value * WetSend; \
299 pos += frac>>FRACTIONBITS; \
300 frac &= FRACTIONMASK; \
303 if(LIKELY(OutPos == SamplesToDo)) \
305 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
306 value = lpFilter1PC(WetFilter, i, value); \
308 WetPendingClicks[0] += value * WetSend; \
310 OutPos -= BufferSize; \
313 *DataPosInt += pos; \
314 *DataPosFrac = frac; \
317 DECL_TEMPLATE(ALfloat
, point32
)
318 DECL_TEMPLATE(ALfloat
, lerp32
)
319 DECL_TEMPLATE(ALfloat
, cubic32
)
321 DECL_TEMPLATE(ALshort
, point16
)
322 DECL_TEMPLATE(ALshort
, lerp16
)
323 DECL_TEMPLATE(ALshort
, cubic16
)
325 DECL_TEMPLATE(ALbyte
, point8
)
326 DECL_TEMPLATE(ALbyte
, lerp8
)
327 DECL_TEMPLATE(ALbyte
, cubic8
)
332 #define DECL_TEMPLATE(T, sampler) \
333 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
334 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
335 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
337 const ALuint NumChannels = Source->NumChannels; \
338 const T *RESTRICT data = srcdata; \
339 ALfloat (*DryBuffer)[MAXCHANNELS]; \
340 ALfloat *ClickRemoval, *PendingClicks; \
342 ALfloat DrySend[MAXCHANNELS][MAXCHANNELS]; \
349 increment = Source->Params.Step; \
351 DryBuffer = Device->DryBuffer; \
352 ClickRemoval = Device->ClickRemoval; \
353 PendingClicks = Device->PendingClicks; \
354 DryFilter = &Source->Params.iirFilter; \
355 for(i = 0;i < NumChannels;i++) \
357 for(c = 0;c < MAXCHANNELS;c++) \
358 DrySend[i][c] = Source->Params.DryGains[i][c]; \
362 frac = *DataPosFrac; \
364 for(i = 0;i < NumChannels;i++) \
367 frac = *DataPosFrac; \
371 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
373 value = lpFilter2PC(DryFilter, i, value); \
374 for(c = 0;c < MAXCHANNELS;c++) \
375 ClickRemoval[c] -= value*DrySend[i][c]; \
377 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
379 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
381 value = lpFilter2P(DryFilter, i, value); \
382 for(c = 0;c < MAXCHANNELS;c++) \
383 DryBuffer[OutPos][c] += value*DrySend[i][c]; \
386 pos += frac>>FRACTIONBITS; \
387 frac &= FRACTIONMASK; \
390 if(OutPos == SamplesToDo) \
392 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
394 value = lpFilter2PC(DryFilter, i, value); \
395 for(c = 0;c < MAXCHANNELS;c++) \
396 PendingClicks[c] += value*DrySend[i][c]; \
398 OutPos -= BufferSize; \
401 for(out = 0;out < Device->NumAuxSends;out++) \
403 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
405 ALfloat *WetBuffer; \
406 ALfloat *WetClickRemoval; \
407 ALfloat *WetPendingClicks; \
410 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
413 WetBuffer = Slot->WetBuffer; \
414 WetClickRemoval = Slot->ClickRemoval; \
415 WetPendingClicks = Slot->PendingClicks; \
416 WetFilter = &Source->Params.Send[out].iirFilter; \
417 WetSend = Source->Params.Send[out].WetGain; \
419 for(i = 0;i < NumChannels;i++) \
422 frac = *DataPosFrac; \
426 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
428 value = lpFilter1PC(WetFilter, i, value); \
429 WetClickRemoval[0] -= value * WetSend; \
431 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
433 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
435 value = lpFilter1P(WetFilter, i, value); \
436 WetBuffer[OutPos] += value * WetSend; \
439 pos += frac>>FRACTIONBITS; \
440 frac &= FRACTIONMASK; \
443 if(OutPos == SamplesToDo) \
445 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
447 value = lpFilter1PC(WetFilter, i, value); \
448 WetPendingClicks[0] += value * WetSend; \
450 OutPos -= BufferSize; \
453 *DataPosInt += pos; \
454 *DataPosFrac = frac; \
457 DECL_TEMPLATE(ALfloat
, point32
)
458 DECL_TEMPLATE(ALfloat
, lerp32
)
459 DECL_TEMPLATE(ALfloat
, cubic32
)
461 DECL_TEMPLATE(ALshort
, point16
)
462 DECL_TEMPLATE(ALshort
, lerp16
)
463 DECL_TEMPLATE(ALshort
, cubic16
)
465 DECL_TEMPLATE(ALbyte
, point8
)
466 DECL_TEMPLATE(ALbyte
, lerp8
)
467 DECL_TEMPLATE(ALbyte
, cubic8
)
472 #define DECL_TEMPLATE(sampler) \
473 static MixerFunc Select_##sampler(enum FmtType FmtType) \
478 return Mix_ALbyte_##sampler##8; \
480 return Mix_ALshort_##sampler##16; \
482 return Mix_ALfloat_##sampler##32; \
493 MixerFunc
SelectMixer(ALbuffer
*Buffer
, enum Resampler Resampler
)
497 case POINT_RESAMPLER
:
498 return Select_point(Buffer
->FmtType
);
499 case LINEAR_RESAMPLER
:
500 return Select_lerp(Buffer
->FmtType
);
501 case CUBIC_RESAMPLER
:
502 return Select_cubic(Buffer
->FmtType
);
510 #define DECL_TEMPLATE(sampler) \
511 static MixerFunc Select_Hrtf_##sampler(enum FmtType FmtType) \
516 return Mix_Hrtf_ALbyte_##sampler##8; \
518 return Mix_Hrtf_ALshort_##sampler##16; \
520 return Mix_Hrtf_ALfloat_##sampler##32; \
531 MixerFunc
SelectHrtfMixer(ALbuffer
*Buffer
, enum Resampler Resampler
)
535 case POINT_RESAMPLER
:
536 return Select_Hrtf_point(Buffer
->FmtType
);
537 case LINEAR_RESAMPLER
:
538 return Select_Hrtf_lerp(Buffer
->FmtType
);
539 case CUBIC_RESAMPLER
:
540 return Select_Hrtf_cubic(Buffer
->FmtType
);
549 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
551 ALbufferlistitem
*BufferListItem
;
552 ALuint DataPosInt
, DataPosFrac
;
553 ALuint BuffersPlayed
;
556 enum Resampler Resampler
;
563 /* Get source info */
564 State
= Source
->state
;
565 BuffersPlayed
= Source
->BuffersPlayed
;
566 DataPosInt
= Source
->position
;
567 DataPosFrac
= Source
->position_fraction
;
568 Looping
= Source
->bLooping
;
569 increment
= Source
->Params
.Step
;
570 Resampler
= Source
->Resampler
;
571 FrameSize
= Source
->NumChannels
* Source
->SampleSize
;
573 /* Get current buffer queue item */
574 BufferListItem
= Source
->queue
;
575 for(i
= 0;i
< BuffersPlayed
;i
++)
576 BufferListItem
= BufferListItem
->next
;
580 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
581 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
582 ALubyte StackData
[STACK_DATA_SIZE
];
583 ALubyte
*SrcData
= StackData
;
584 ALuint SrcDataSize
= 0;
587 /* Figure out how many buffer bytes will be needed */
588 DataSize64
= SamplesToDo
-OutPos
+1;
589 DataSize64
*= increment
;
590 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
591 DataSize64
>>= FRACTIONBITS
;
592 DataSize64
+= BufferPadding
+BufferPrePadding
;
593 DataSize64
*= FrameSize
;
595 BufferSize
= ((DataSize64
> STACK_DATA_SIZE
) ? STACK_DATA_SIZE
: DataSize64
);
596 BufferSize
-= BufferSize
%FrameSize
;
598 if(Source
->lSourceType
== AL_STATIC
)
600 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
601 const ALubyte
*Data
= ALBuffer
->data
;
605 /* If current pos is beyond the loop range, do not loop */
606 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
610 if(DataPosInt
>= BufferPrePadding
)
611 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
614 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
615 DataSize
= minu(BufferSize
, DataSize
);
617 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
618 SrcDataSize
+= DataSize
;
619 BufferSize
-= DataSize
;
624 /* Copy what's left to play in the source buffer, and clear the
625 * rest of the temp buffer */
626 DataSize
= ALBuffer
->size
- pos
;
627 DataSize
= minu(BufferSize
, DataSize
);
629 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
630 SrcDataSize
+= DataSize
;
631 BufferSize
-= DataSize
;
633 memset(&SrcData
[SrcDataSize
], 0, BufferSize
);
634 SrcDataSize
+= BufferSize
;
635 BufferSize
-= BufferSize
;
639 ALuint LoopStart
= ALBuffer
->LoopStart
;
640 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
642 if(DataPosInt
>= LoopStart
)
644 pos
= DataPosInt
-LoopStart
;
645 while(pos
< BufferPrePadding
)
646 pos
+= LoopEnd
-LoopStart
;
647 pos
-= BufferPrePadding
;
651 else if(DataPosInt
>= BufferPrePadding
)
652 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
655 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
656 DataSize
= minu(BufferSize
, DataSize
);
658 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
659 SrcDataSize
+= DataSize
;
660 BufferSize
-= DataSize
;
665 /* Copy what's left of this loop iteration, then copy repeats
666 * of the loop section */
667 DataSize
= LoopEnd
*FrameSize
- pos
;
668 DataSize
= minu(BufferSize
, DataSize
);
670 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
671 SrcDataSize
+= DataSize
;
672 BufferSize
-= DataSize
;
674 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
675 while(BufferSize
> 0)
677 DataSize
= minu(BufferSize
, DataSize
);
679 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
680 SrcDataSize
+= DataSize
;
681 BufferSize
-= DataSize
;
687 /* Crawl the buffer queue to fill in the temp buffer */
688 ALbufferlistitem
*BufferListIter
= BufferListItem
;
691 if(DataPosInt
>= BufferPrePadding
)
692 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
695 pos
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
698 if(!BufferListIter
->prev
&& !Looping
)
700 ALuint DataSize
= minu(BufferSize
, pos
);
702 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
703 SrcDataSize
+= DataSize
;
704 BufferSize
-= DataSize
;
710 if(BufferListIter
->prev
)
711 BufferListIter
= BufferListIter
->prev
;
714 while(BufferListIter
->next
)
715 BufferListIter
= BufferListIter
->next
;
718 if(BufferListIter
->buffer
)
720 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
722 pos
= BufferListIter
->buffer
->size
- pos
;
725 pos
-= BufferListIter
->buffer
->size
;
730 while(BufferListIter
&& BufferSize
> 0)
732 const ALbuffer
*ALBuffer
;
733 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
735 const ALubyte
*Data
= ALBuffer
->data
;
736 ALuint DataSize
= ALBuffer
->size
;
738 /* Skip the data already played */
747 DataSize
= minu(BufferSize
, DataSize
);
748 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
749 SrcDataSize
+= DataSize
;
750 BufferSize
-= DataSize
;
753 BufferListIter
= BufferListIter
->next
;
754 if(!BufferListIter
&& Looping
)
755 BufferListIter
= Source
->queue
;
756 else if(!BufferListIter
)
758 memset(&SrcData
[SrcDataSize
], 0, BufferSize
);
759 SrcDataSize
+= BufferSize
;
760 BufferSize
-= BufferSize
;
765 /* Figure out how many samples we can mix. */
766 DataSize64
= SrcDataSize
/ FrameSize
;
767 DataSize64
-= BufferPadding
+BufferPrePadding
;
768 DataSize64
<<= FRACTIONBITS
;
769 DataSize64
-= increment
;
770 DataSize64
-= DataPosFrac
;
772 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
773 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
775 SrcData
+= BufferPrePadding
*FrameSize
;
776 Source
->Params
.DoMix(Source
, Device
, SrcData
, &DataPosInt
, &DataPosFrac
,
777 OutPos
, SamplesToDo
, BufferSize
);
778 OutPos
+= BufferSize
;
780 /* Handle looping sources */
783 const ALbuffer
*ALBuffer
;
785 ALuint LoopStart
= 0;
788 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
790 DataSize
= ALBuffer
->size
/ FrameSize
;
791 LoopStart
= ALBuffer
->LoopStart
;
792 LoopEnd
= ALBuffer
->LoopEnd
;
793 if(LoopEnd
> DataPosInt
)
797 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
799 BufferListItem
= Source
->queue
;
800 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
804 if(DataSize
> DataPosInt
)
807 if(BufferListItem
->next
)
809 BufferListItem
= BufferListItem
->next
;
814 BufferListItem
= Source
->queue
;
820 BufferListItem
= Source
->queue
;
821 BuffersPlayed
= Source
->BuffersInQueue
;
827 DataPosInt
-= DataSize
;
829 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
831 /* Update source info */
832 Source
->state
= State
;
833 Source
->BuffersPlayed
= BuffersPlayed
;
834 Source
->position
= DataPosInt
;
835 Source
->position_fraction
= DataPosFrac
;
836 Source
->HrtfOffset
+= OutPos
;
837 if(State
== AL_PLAYING
)
839 Source
->HrtfCounter
= maxu(Source
->HrtfCounter
, OutPos
) - OutPos
;
840 Source
->HrtfMoving
= AL_TRUE
;
844 Source
->HrtfCounter
= 0;
845 Source
->HrtfMoving
= AL_FALSE
;