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(ALfloat val1
, ALfloat val2
, ALint frac
)
46 static __inline ALfloat
lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
48 val1
+= ((val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
))));
51 static __inline ALfloat
cos_lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
53 val1
+= ((val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5));
57 static __inline ALfloat
point16(ALfloat val1
, ALfloat val2
, ALint frac
)
59 return val1
/ 32767.0f
;
63 static __inline ALfloat
lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
65 val1
+= (val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
)));
66 return val1
/ 32767.0f
;
68 static __inline ALfloat
cos_lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
70 val1
+= (val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5);
71 return val1
/ 32767.0f
;
75 #define DECL_MIX_MONO(T,sampler) \
76 static void MixMono_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
77 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
78 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
80 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
81 ALfloat *ClickRemoval, *PendingClicks; \
83 ALfloat DrySend[OUTPUTCHANNELS]; \
90 increment = Source->Params.Step; \
92 DryBuffer = Device->DryBuffer; \
93 ClickRemoval = Device->ClickRemoval; \
94 PendingClicks = Device->PendingClicks; \
95 DryFilter = &Source->Params.iirFilter; \
96 for(i = 0;i < OUTPUTCHANNELS;i++) \
97 DrySend[i] = Source->Params.DryGains[i]; \
100 frac = *DataPosFrac; \
104 value = sampler(data[pos], data[pos+1], frac); \
106 value = lpFilter4PC(DryFilter, 0, value); \
107 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
108 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
109 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
110 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
111 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
112 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
113 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
114 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
116 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
118 /* First order interpolator */ \
119 value = sampler(data[pos], data[pos+1], frac); \
121 /* Direct path final mix buffer and panning */ \
122 value = lpFilter4P(DryFilter, 0, value); \
123 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
124 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
125 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
126 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
127 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
128 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
129 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
130 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
133 pos += frac>>FRACTIONBITS; \
134 frac &= FRACTIONMASK; \
137 if(j == SamplesToDo) \
143 ALuint64 pos64 = pos; \
144 pos64 <<= FRACTIONBITS; \
146 pos64 -= increment; \
147 p = pos64>>FRACTIONBITS; \
148 f = pos64&FRACTIONMASK; \
150 value = sampler(data[p], data[p+1], f); \
152 value = lpFilter4PC(DryFilter, 0, value); \
153 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
154 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
155 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
156 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
157 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
158 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
159 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
160 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
163 for(out = 0;out < Device->NumAuxSends;out++) \
166 ALfloat *WetBuffer; \
167 ALfloat *WetClickRemoval; \
168 ALfloat *WetPendingClicks; \
171 if(!Source->Send[out].Slot || \
172 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
175 WetBuffer = Source->Send[out].Slot->WetBuffer; \
176 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
177 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
178 WetFilter = &Source->Params.Send[out].iirFilter; \
179 WetSend = Source->Params.Send[out].WetGain; \
182 frac = *DataPosFrac; \
187 value = sampler(data[pos], data[pos+1], frac); \
189 value = lpFilter2PC(WetFilter, 0, value); \
190 WetClickRemoval[0] -= value*WetSend; \
192 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
194 /* First order interpolator */ \
195 value = sampler(data[pos], data[pos+1], frac); \
197 /* Room path final mix buffer and panning */ \
198 value = lpFilter2P(WetFilter, 0, value); \
199 WetBuffer[j] += value*WetSend; \
202 pos += frac>>FRACTIONBITS; \
203 frac &= FRACTIONMASK; \
206 if(j == SamplesToDo) \
212 ALuint64 pos64 = pos; \
213 pos64 <<= FRACTIONBITS; \
215 pos64 -= increment; \
216 p = pos64>>FRACTIONBITS; \
217 f = pos64&FRACTIONMASK; \
219 value = sampler(data[p], data[p+1], f); \
221 value = lpFilter2PC(WetFilter, 0, value); \
222 WetPendingClicks[0] += value*WetSend; \
226 *DataPosFrac = frac; \
229 DECL_MIX_MONO(ALfloat
, point32
)
230 DECL_MIX_MONO(ALfloat
, lerp32
)
231 DECL_MIX_MONO(ALfloat
, cos_lerp32
)
233 DECL_MIX_MONO(ALshort
, point16
)
234 DECL_MIX_MONO(ALshort
, lerp16
)
235 DECL_MIX_MONO(ALshort
, cos_lerp16
)
238 #define DECL_MIX_STEREO(T,sampler) \
239 static void MixStereo_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
240 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
241 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
243 static const ALuint Channels = 2; \
244 static const Channel chans[] = { \
245 FRONT_LEFT, FRONT_RIGHT, \
246 SIDE_LEFT, SIDE_RIGHT, \
247 BACK_LEFT, BACK_RIGHT \
249 const ALfloat scaler = 1.0f/Channels; \
250 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
251 ALfloat *ClickRemoval, *PendingClicks; \
253 ALfloat DrySend[OUTPUTCHANNELS]; \
260 increment = Source->Params.Step; \
262 DryBuffer = Device->DryBuffer; \
263 ClickRemoval = Device->ClickRemoval; \
264 PendingClicks = Device->PendingClicks; \
265 DryFilter = &Source->Params.iirFilter; \
266 for(i = 0;i < OUTPUTCHANNELS;i++) \
267 DrySend[i] = Source->Params.DryGains[i]; \
270 frac = *DataPosFrac; \
274 for(i = 0;i < Channels;i++) \
276 value = sampler(data[pos*Channels + i], \
277 data[(pos+1)*Channels + i], frac); \
279 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
280 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
281 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
282 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
285 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
287 for(i = 0;i < Channels;i++) \
289 value = sampler(data[pos*Channels + i], \
290 data[(pos+1)*Channels + i], frac); \
292 value = lpFilter2P(DryFilter, chans[i]*2, value); \
293 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
294 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
295 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
299 pos += frac>>FRACTIONBITS; \
300 frac &= FRACTIONMASK; \
303 if(j == SamplesToDo) \
309 ALuint64 pos64 = pos; \
310 pos64 <<= FRACTIONBITS; \
312 pos64 -= increment; \
313 p = pos64>>FRACTIONBITS; \
314 f = pos64&FRACTIONMASK; \
316 for(i = 0;i < Channels;i++) \
318 value = sampler(data[p*Channels + i], \
319 data[(p+1)*Channels + i], f); \
321 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
322 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
323 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
324 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
328 for(out = 0;out < Device->NumAuxSends;out++) \
331 ALfloat *WetBuffer; \
332 ALfloat *WetClickRemoval; \
333 ALfloat *WetPendingClicks; \
336 if(!Source->Send[out].Slot || \
337 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
340 WetBuffer = Source->Send[out].Slot->WetBuffer; \
341 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
342 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
343 WetFilter = &Source->Params.Send[out].iirFilter; \
344 WetSend = Source->Params.Send[out].WetGain; \
347 frac = *DataPosFrac; \
352 for(i = 0;i < Channels;i++) \
354 value = sampler(data[pos*Channels + i], \
355 data[(pos+1)*Channels + i], frac); \
357 value = lpFilter1PC(WetFilter, chans[i], value); \
358 WetClickRemoval[0] -= value*WetSend * scaler; \
361 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
363 for(i = 0;i < Channels;i++) \
365 value = sampler(data[pos*Channels + i], \
366 data[(pos+1)*Channels + i], frac); \
368 value = lpFilter1P(WetFilter, chans[i], value); \
369 WetBuffer[j] += value*WetSend * scaler; \
373 pos += frac>>FRACTIONBITS; \
374 frac &= FRACTIONMASK; \
377 if(j == SamplesToDo) \
383 ALuint64 pos64 = pos; \
384 pos64 <<= FRACTIONBITS; \
386 pos64 -= increment; \
387 p = pos64>>FRACTIONBITS; \
388 f = pos64&FRACTIONMASK; \
390 for(i = 0;i < Channels;i++) \
392 value = sampler(data[p*Channels + i], \
393 data[(p+1)*Channels + i], f); \
395 value = lpFilter1PC(WetFilter, chans[i], value); \
396 WetPendingClicks[0] += value*WetSend * scaler; \
401 *DataPosFrac = frac; \
404 DECL_MIX_STEREO(ALfloat
, point32
)
405 DECL_MIX_STEREO(ALfloat
, lerp32
)
406 DECL_MIX_STEREO(ALfloat
, cos_lerp32
)
408 DECL_MIX_STEREO(ALshort
, point16
)
409 DECL_MIX_STEREO(ALshort
, lerp16
)
410 DECL_MIX_STEREO(ALshort
, cos_lerp16
)
414 #define DECL_MIX_MC(T,chans,sampler) \
415 static void MixMC_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
416 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
417 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
419 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
420 const ALfloat scaler = 1.0f/Channels; \
421 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
422 ALfloat *ClickRemoval, *PendingClicks; \
424 ALfloat DrySend[OUTPUTCHANNELS]; \
431 increment = Source->Params.Step; \
433 DryBuffer = Device->DryBuffer; \
434 ClickRemoval = Device->ClickRemoval; \
435 PendingClicks = Device->PendingClicks; \
436 DryFilter = &Source->Params.iirFilter; \
437 for(i = 0;i < OUTPUTCHANNELS;i++) \
438 DrySend[i] = Source->Params.DryGains[i]; \
441 frac = *DataPosFrac; \
445 for(i = 0;i < Channels;i++) \
447 value = sampler(data[pos*Channels + i], \
448 data[(pos+1)*Channels + i], frac); \
450 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
451 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
454 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
456 for(i = 0;i < Channels;i++) \
458 value = sampler(data[pos*Channels + i], \
459 data[(pos+1)*Channels + i], frac); \
461 value = lpFilter2P(DryFilter, chans[i]*2, value); \
462 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
466 pos += frac>>FRACTIONBITS; \
467 frac &= FRACTIONMASK; \
470 if(j == SamplesToDo) \
476 ALuint64 pos64 = pos; \
477 pos64 <<= FRACTIONBITS; \
479 pos64 -= increment; \
480 p = pos64>>FRACTIONBITS; \
481 f = pos64&FRACTIONMASK; \
483 for(i = 0;i < Channels;i++) \
485 value = sampler(data[p*Channels + i], \
486 data[(p+1)*Channels + i], f); \
488 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
489 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
493 for(out = 0;out < Device->NumAuxSends;out++) \
496 ALfloat *WetBuffer; \
497 ALfloat *WetClickRemoval; \
498 ALfloat *WetPendingClicks; \
501 if(!Source->Send[out].Slot || \
502 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
505 WetBuffer = Source->Send[out].Slot->WetBuffer; \
506 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
507 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
508 WetFilter = &Source->Params.Send[out].iirFilter; \
509 WetSend = Source->Params.Send[out].WetGain; \
512 frac = *DataPosFrac; \
517 for(i = 0;i < Channels;i++) \
519 value = sampler(data[pos*Channels + i], \
520 data[(pos+1)*Channels + i], frac); \
522 value = lpFilter1PC(WetFilter, chans[i], value); \
523 WetClickRemoval[0] -= value*WetSend * scaler; \
526 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
528 for(i = 0;i < Channels;i++) \
530 value = sampler(data[pos*Channels + i], \
531 data[(pos+1)*Channels + i], frac); \
533 value = lpFilter1P(WetFilter, chans[i], value); \
534 WetBuffer[j] += value*WetSend * scaler; \
538 pos += frac>>FRACTIONBITS; \
539 frac &= FRACTIONMASK; \
542 if(j == SamplesToDo) \
548 ALuint64 pos64 = pos; \
549 pos64 <<= FRACTIONBITS; \
551 pos64 -= increment; \
552 p = pos64>>FRACTIONBITS; \
553 f = pos64&FRACTIONMASK; \
555 for(i = 0;i < Channels;i++) \
557 value = sampler(data[p*Channels + i], \
558 data[(p+1)*Channels + i], f); \
560 value = lpFilter1PC(WetFilter, chans[i], value); \
561 WetPendingClicks[0] += value*WetSend * scaler; \
566 *DataPosFrac = frac; \
569 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
570 BACK_LEFT
, BACK_RIGHT
};
571 DECL_MIX_MC(ALfloat
, QuadChans
, point32
)
572 DECL_MIX_MC(ALfloat
, QuadChans
, lerp32
)
573 DECL_MIX_MC(ALfloat
, QuadChans
, cos_lerp32
)
575 DECL_MIX_MC(ALshort
, QuadChans
, point16
)
576 DECL_MIX_MC(ALshort
, QuadChans
, lerp16
)
577 DECL_MIX_MC(ALshort
, QuadChans
, cos_lerp16
)
580 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
582 BACK_LEFT
, BACK_RIGHT
};
583 DECL_MIX_MC(ALfloat
, X51Chans
, point32
)
584 DECL_MIX_MC(ALfloat
, X51Chans
, lerp32
)
585 DECL_MIX_MC(ALfloat
, X51Chans
, cos_lerp32
)
587 DECL_MIX_MC(ALshort
, X51Chans
, point16
)
588 DECL_MIX_MC(ALshort
, X51Chans
, lerp16
)
589 DECL_MIX_MC(ALshort
, X51Chans
, cos_lerp16
)
592 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
595 SIDE_LEFT
, SIDE_RIGHT
};
596 DECL_MIX_MC(ALfloat
, X61Chans
, point32
)
597 DECL_MIX_MC(ALfloat
, X61Chans
, lerp32
)
598 DECL_MIX_MC(ALfloat
, X61Chans
, cos_lerp32
)
600 DECL_MIX_MC(ALshort
, X61Chans
, point16
)
601 DECL_MIX_MC(ALshort
, X61Chans
, lerp16
)
602 DECL_MIX_MC(ALshort
, X61Chans
, cos_lerp16
)
605 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
607 BACK_LEFT
, BACK_RIGHT
,
608 SIDE_LEFT
, SIDE_RIGHT
};
609 DECL_MIX_MC(ALfloat
, X71Chans
, point32
)
610 DECL_MIX_MC(ALfloat
, X71Chans
, lerp32
)
611 DECL_MIX_MC(ALfloat
, X71Chans
, cos_lerp32
)
613 DECL_MIX_MC(ALshort
, X71Chans
, point16
)
614 DECL_MIX_MC(ALshort
, X71Chans
, lerp16
)
615 DECL_MIX_MC(ALshort
, X71Chans
, cos_lerp16
)
618 #define DECL_MIX(T, sampler) \
619 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
620 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd,\
621 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
626 MixMono_##T##_##sampler(Source, Device, \
627 Data, DataPosInt, DataPosFrac, DataEnd, \
628 j, SamplesToDo, BufferSize); \
630 case 2: /* Stereo */ \
631 MixStereo_##T##_##sampler(Source, Device, \
632 Data, DataPosInt, DataPosFrac, DataEnd, \
633 j, SamplesToDo, BufferSize); \
636 MixMC_##T##_QuadChans_##sampler(Source, Device, \
637 Data, DataPosInt, DataPosFrac, DataEnd, \
638 j, SamplesToDo, BufferSize); \
641 MixMC_##T##_X51Chans_##sampler(Source, Device, \
642 Data, DataPosInt, DataPosFrac, DataEnd, \
643 j, SamplesToDo, BufferSize); \
646 MixMC_##T##_X61Chans_##sampler(Source, Device, \
647 Data, DataPosInt, DataPosFrac, DataEnd, \
648 j, SamplesToDo, BufferSize); \
651 MixMC_##T##_X71Chans_##sampler(Source, Device, \
652 Data, DataPosInt, DataPosFrac, DataEnd, \
653 j, SamplesToDo, BufferSize); \
658 DECL_MIX(ALfloat
, point32
)
659 DECL_MIX(ALfloat
, lerp32
)
660 DECL_MIX(ALfloat
, cos_lerp32
)
662 DECL_MIX(ALshort
, point16
)
663 DECL_MIX(ALshort
, lerp16
)
664 DECL_MIX(ALshort
, cos_lerp16
)
667 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
669 ALbufferlistitem
*BufferListItem
;
670 ALint64 DataSize64
,DataPos64
;
672 ALuint DataPosInt
, DataPosFrac
;
673 ALuint BuffersPlayed
;
678 /* Get source info */
679 State
= Source
->state
;
680 BuffersPlayed
= Source
->BuffersPlayed
;
681 DataPosInt
= Source
->position
;
682 DataPosFrac
= Source
->position_fraction
;
683 Looping
= Source
->bLooping
;
685 /* Get current buffer queue item */
686 BufferListItem
= Source
->queue
;
687 for(i
= 0;i
< BuffersPlayed
;i
++)
688 BufferListItem
= BufferListItem
->next
;
692 const ALbuffer
*ALBuffer
;
693 ALubyte
*Data
= NULL
;
695 ALuint LoopStart
= 0;
697 ALuint Channels
, Bytes
;
700 /* Get buffer info */
701 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
703 Data
= ALBuffer
->data
;
704 DataSize
= ALBuffer
->size
;
705 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
706 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
707 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
711 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
713 /* If current pos is beyond the loop range, do not loop */
714 if(DataPosInt
>= LoopEnd
)
718 LoopStart
= ALBuffer
->LoopStart
;
719 LoopEnd
= ALBuffer
->LoopEnd
;
724 if(DataPosInt
>= DataSize
)
727 memset(&Data
[DataSize
*Channels
*Bytes
], 0, BUFFER_PADDING
*Channels
*Bytes
);
728 if(BufferListItem
->next
)
730 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
731 if(NextBuf
&& NextBuf
->size
)
733 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
734 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
735 memcpy(&Data
[DataSize
*Channels
*Bytes
],
736 NextBuf
->data
, ulExtraSamples
);
741 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
742 if(NextBuf
&& NextBuf
->size
)
744 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
745 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
746 memcpy(&Data
[DataSize
*Channels
*Bytes
],
747 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
752 /* Figure out how many samples we can mix. */
753 increment
= Source
->Params
.Step
;
754 DataSize64
= LoopEnd
;
755 DataSize64
<<= FRACTIONBITS
;
756 DataPos64
= DataPosInt
;
757 DataPos64
<<= FRACTIONBITS
;
758 DataPos64
+= DataPosFrac
;
759 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
761 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
763 switch(Source
->Resampler
)
765 case POINT_RESAMPLER
:
767 Mix_ALfloat_point32(Source
, Device
, Channels
,
768 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
769 j
, SamplesToDo
, BufferSize
);
771 Mix_ALshort_point16(Source
, Device
, Channels
,
772 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
773 j
, SamplesToDo
, BufferSize
);
775 case LINEAR_RESAMPLER
:
777 Mix_ALfloat_lerp32(Source
, Device
, Channels
,
778 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
779 j
, SamplesToDo
, BufferSize
);
781 Mix_ALshort_lerp16(Source
, Device
, Channels
,
782 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
783 j
, SamplesToDo
, BufferSize
);
785 case COSINE_RESAMPLER
:
787 Mix_ALfloat_cos_lerp32(Source
, Device
, Channels
,
788 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
789 j
, SamplesToDo
, BufferSize
);
791 Mix_ALshort_cos_lerp16(Source
, Device
, Channels
,
792 Data
, &DataPosInt
, &DataPosFrac
, LoopEnd
,
793 j
, SamplesToDo
, BufferSize
);
802 /* Handle looping sources */
803 if(DataPosInt
>= LoopEnd
)
805 if(BufferListItem
->next
)
807 BufferListItem
= BufferListItem
->next
;
809 DataPosInt
-= DataSize
;
813 BufferListItem
= Source
->queue
;
815 if(Source
->lSourceType
== AL_STATIC
)
816 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
818 DataPosInt
-= DataSize
;
823 BufferListItem
= Source
->queue
;
824 BuffersPlayed
= Source
->BuffersInQueue
;
829 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
831 /* Update source info */
832 Source
->state
= State
;
833 Source
->BuffersPlayed
= BuffersPlayed
;
834 Source
->position
= DataPosInt
;
835 Source
->position_fraction
= DataPosFrac
;
836 Source
->Buffer
= BufferListItem
->buffer
;