Add a config option to disable use of CPU extensions
[openal-soft/openal-hmr.git] / Alc / mixer.c
blobe7fada8f0d89639fe2fa89d467fd1ee5e4ca54dd
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #ifdef HAVE_ARM_NEON_H
29 #include <arm_neon.h>
30 #endif
32 #include "alMain.h"
33 #include "AL/al.h"
34 #include "AL/alc.h"
35 #include "alSource.h"
36 #include "alBuffer.h"
37 #include "alListener.h"
38 #include "alAuxEffectSlot.h"
39 #include "alu.h"
40 #include "bs2b.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)); }
51 #ifdef __GNUC__
52 #define LIKELY(x) __builtin_expect(!!(x), 1)
53 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
54 #else
55 #define LIKELY(x) (x)
56 #define UNLIKELY(x) (x)
57 #endif
59 static __inline void ApplyCoeffsC(ALuint Offset, ALfloat (*RESTRICT Values)[2],
60 ALfloat (*RESTRICT Coeffs)[2],
61 ALfloat left, ALfloat right)
63 ALuint c;
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) \
77 { \
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; \
83 ALuint pos, frac; \
84 FILTER *DryFilter; \
85 ALuint BufferIdx; \
86 ALuint increment; \
87 ALfloat value; \
88 ALuint i, c; \
90 increment = Source->Params.Step; \
92 DryBuffer = Device->DryBuffer; \
93 ClickRemoval = Device->ClickRemoval; \
94 PendingClicks = Device->PendingClicks; \
95 DryFilter = &params->iirFilter; \
97 for(i = 0;i < NumChannels;i++) \
98 { \
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]; \
106 ALuint Delay[2]; \
107 ALfloat left, right; \
109 pos = 0; \
110 frac = srcfrac; \
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; \
157 Offset++; \
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]; \
171 frac += increment; \
172 pos += frac>>FRACTIONBITS; \
173 frac &= FRACTIONMASK; \
174 OutPos++; \
175 Counter--; \
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; \
191 Offset++; \
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]; \
197 frac += increment; \
198 pos += frac>>FRACTIONBITS; \
199 frac &= FRACTIONMASK; \
200 OutPos++; \
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)
230 ALuint c;
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)
257 #endif
259 #undef DECL_TEMPLATE
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]; \
271 FILTER *DryFilter; \
272 ALuint pos, frac; \
273 ALuint BufferIdx; \
274 ALuint increment; \
275 ALfloat value; \
276 ALuint i, c; \
278 increment = Source->Params.Step; \
280 DryBuffer = Device->DryBuffer; \
281 ClickRemoval = Device->ClickRemoval; \
282 PendingClicks = Device->PendingClicks; \
283 DryFilter = &params->iirFilter; \
285 for(i = 0;i < NumChannels;i++) \
287 for(c = 0;c < MaxChannels;c++) \
288 DrySend[c] = params->Gains[i][c]; \
290 pos = 0; \
291 frac = srcfrac; \
293 if(OutPos == 0) \
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]; \
309 frac += increment; \
310 pos += frac>>FRACTIONBITS; \
311 frac &= FRACTIONMASK; \
312 OutPos++; \
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)
330 #undef DECL_TEMPLATE
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; \
339 ALfloat WetSend; \
340 ALfloat *WetBuffer; \
341 ALfloat *WetClickRemoval; \
342 ALfloat *WetPendingClicks; \
343 FILTER *WetFilter; \
344 ALuint pos, frac; \
345 ALuint BufferIdx; \
346 ALuint increment; \
347 ALfloat value; \
348 ALuint i; \
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 = &params->iirFilter; \
357 WetSend = params->Gain; \
359 for(i = 0;i < NumChannels;i++) \
361 pos = 0; \
362 frac = srcfrac; \
364 if(OutPos == 0) \
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; \
378 frac += increment; \
379 pos += frac>>FRACTIONBITS; \
380 frac &= FRACTIONMASK; \
381 OutPos++; \
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)
398 #undef DECL_TEMPLATE
401 DryMixerFunc SelectDirectMixer(enum Resampler Resampler)
403 switch(Resampler)
405 case PointResampler:
406 return MixDirect_point32;
407 case LinearResampler:
408 return MixDirect_lerp32;
409 case CubicResampler:
410 return MixDirect_cubic32;
411 case ResamplerMax:
412 break;
414 return NULL;
417 DryMixerFunc SelectHrtfMixer(enum Resampler Resampler)
419 switch(Resampler)
421 case PointResampler:
422 #ifdef HAVE_ARM_NEON_H
423 if((CPUCapFlags&CPU_CAP_NEON))
424 return MixDirect_Hrtf_point32_Neon;
425 #endif
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;
431 #endif
432 return MixDirect_Hrtf_lerp32_C;
433 case CubicResampler:
434 #ifdef HAVE_ARM_NEON_H
435 if((CPUCapFlags&CPU_CAP_NEON))
436 return MixDirect_Hrtf_cubic32_Neon;
437 #endif
438 return MixDirect_Hrtf_cubic32_C;
439 case ResamplerMax:
440 break;
442 return NULL;
445 WetMixerFunc SelectSendMixer(enum Resampler Resampler)
447 switch(Resampler)
449 case PointResampler:
450 return MixSend_point32;
451 case LinearResampler:
452 return MixSend_lerp32;
453 case CubicResampler:
454 return MixSend_cubic32;
455 case ResamplerMax:
456 break;
458 return NULL;
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)
469 { return val; }
471 #define DECL_TEMPLATE(T) \
472 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
474 ALuint i; \
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)
483 #undef DECL_TEMPLATE
485 static void LoadStack(ALfloat *dst, const ALvoid *src, enum FmtType srctype, ALuint samples)
487 switch(srctype)
489 case FmtByte:
490 Load_ALbyte(dst, src, samples);
491 break;
492 case FmtShort:
493 Load_ALshort(dst, src, samples);
494 break;
495 case FmtFloat:
496 Load_ALfloat(dst, src, samples);
497 break;
501 static void SilenceStack(ALfloat *dst, ALuint samples)
503 ALuint i;
504 for(i = 0;i < samples;i++)
505 dst[i] = 0.0f;
509 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
511 ALbufferlistitem *BufferListItem;
512 ALuint DataPosInt, DataPosFrac;
513 ALuint BuffersPlayed;
514 ALboolean Looping;
515 ALuint increment;
516 enum Resampler Resampler;
517 ALenum State;
518 ALuint OutPos;
519 ALuint NumChannels;
520 ALuint FrameSize;
521 ALint64 DataSize64;
522 ALuint i;
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;
540 OutPos = 0;
541 do {
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;
547 ALuint BufferSize;
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;
564 ALuint DataSize;
565 ALuint pos;
567 /* If current pos is beyond the loop range, do not loop */
568 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
570 Looping = AL_FALSE;
572 if(DataPosInt >= BufferPrePadding)
573 pos = DataPosInt - BufferPrePadding;
574 else
576 DataSize = BufferPrePadding - DataPosInt;
577 DataSize = minu(BufferSize, DataSize);
579 SilenceStack(&SrcData[SrcDataSize*NumChannels],
580 DataSize*NumChannels);
581 SrcDataSize += DataSize;
582 BufferSize -= DataSize;
584 pos = 0;
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;
602 else
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;
613 pos += LoopStart;
615 else if(DataPosInt >= BufferPrePadding)
616 pos = DataPosInt - BufferPrePadding;
617 else
619 DataSize = BufferPrePadding - DataPosInt;
620 DataSize = minu(BufferSize, DataSize);
622 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
623 SrcDataSize += DataSize;
624 BufferSize -= DataSize;
626 pos = 0;
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;
651 else
653 /* Crawl the buffer queue to fill in the temp buffer */
654 ALbufferlistitem *tmpiter = BufferListItem;
655 ALuint pos;
657 if(DataPosInt >= BufferPrePadding)
658 pos = DataPosInt - BufferPrePadding;
659 else
661 pos = BufferPrePadding - DataPosInt;
662 while(pos > 0)
664 if(!tmpiter->prev && !Looping)
666 ALuint DataSize = minu(BufferSize, pos);
668 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
669 SrcDataSize += DataSize;
670 BufferSize -= DataSize;
672 pos = 0;
673 break;
676 if(tmpiter->prev)
677 tmpiter = tmpiter->prev;
678 else
680 while(tmpiter->next)
681 tmpiter = tmpiter->next;
684 if(tmpiter->buffer)
686 if((ALuint)tmpiter->buffer->SampleLen > pos)
688 pos = tmpiter->buffer->SampleLen - pos;
689 break;
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 */
705 if(DataSize <= pos)
706 pos -= DataSize;
707 else
709 Data += pos*FrameSize;
710 DataSize -= pos;
711 pos -= pos;
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;
723 else if(!tmpiter)
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])
749 continue;
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;
759 OutPos++;
762 /* Handle looping sources */
763 while(1)
765 const ALbuffer *ALBuffer;
766 ALuint DataSize = 0;
767 ALuint LoopStart = 0;
768 ALuint LoopEnd = 0;
770 if((ALBuffer=BufferListItem->buffer) != NULL)
772 DataSize = ALBuffer->SampleLen;
773 LoopStart = ALBuffer->LoopStart;
774 LoopEnd = ALBuffer->LoopEnd;
775 if(LoopEnd > DataPosInt)
776 break;
779 if(Looping && Source->SourceType == AL_STATIC)
781 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
782 break;
785 if(DataSize > DataPosInt)
786 break;
788 if(BufferListItem->next)
790 BufferListItem = BufferListItem->next;
791 BuffersPlayed++;
793 else if(Looping)
795 BufferListItem = Source->queue;
796 BuffersPlayed = 0;
798 else
800 State = AL_STOPPED;
801 BufferListItem = Source->queue;
802 BuffersPlayed = Source->BuffersInQueue;
803 DataPosInt = 0;
804 DataPosFrac = 0;
805 break;
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;
823 else
825 Source->Hrtf.Counter = 0;
826 Source->Hrtf.Moving = AL_FALSE;