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 ALubyte *vals, ALint step, ALint frac)
57
{ return (vals[0]-128.0) * (1.0/127.0); (void)step; (void)frac; }
58
static __inline ALdouble lerp8(const ALubyte *vals, ALint step, ALint frac)
59
{ return (lerp(vals[0], vals[step],
60
frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
61
static __inline ALdouble cubic8(const ALubyte *vals, ALint step, ALint frac)
62
{ return (cubic(vals[-step], vals[0], vals[step], vals[step+step],
63
frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
66
#define DECL_TEMPLATE(T, sampler) \
67
static void Mix_##T##_1_##sampler(ALsource *Source, ALCdevice *Device, \
68
const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
69
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
71
ALfloat (*DryBuffer)[MAXCHANNELS]; \
72
ALfloat *ClickRemoval, *PendingClicks; \
74
ALfloat DrySend[MAXCHANNELS]; \
81
increment = Source->Params.Step; \
83
DryBuffer = Device->DryBuffer; \
84
ClickRemoval = Device->ClickRemoval; \
85
PendingClicks = Device->PendingClicks; \
86
DryFilter = &Source->Params.iirFilter; \
87
for(c = 0;c < MAXCHANNELS;c++) \
88
DrySend[c] = Source->Params.DryGains[0][c]; \
91
frac = *DataPosFrac; \
95
value = sampler(data+pos, 1, frac); \
97
value = lpFilter4PC(DryFilter, 0, value); \
98
for(c = 0;c < MAXCHANNELS;c++) \
99
ClickRemoval[c] -= value*DrySend[c]; \
101
for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
103
/* First order interpolator */ \
104
value = sampler(data+pos, 1, frac); \
106
/* Direct path final mix buffer and panning */ \
107
value = lpFilter4P(DryFilter, 0, value); \
108
for(c = 0;c < MAXCHANNELS;c++) \
109
DryBuffer[OutPos][c] += value*DrySend[c]; \
112
pos += frac>>FRACTIONBITS; \
113
frac &= FRACTIONMASK; \
116
if(OutPos == SamplesToDo) \
118
value = sampler(data+pos, 1, frac); \
120
value = lpFilter4PC(DryFilter, 0, value); \
121
for(c = 0;c < MAXCHANNELS;c++) \
122
PendingClicks[c] += value*DrySend[c]; \
125
for(out = 0;out < Device->NumAuxSends;out++) \
128
ALfloat *WetBuffer; \
129
ALfloat *WetClickRemoval; \
130
ALfloat *WetPendingClicks; \
133
if(!Source->Send[out].Slot || \
134
Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
137
WetBuffer = Source->Send[out].Slot->WetBuffer; \
138
WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
139
WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
140
WetFilter = &Source->Params.Send[out].iirFilter; \
141
WetSend = Source->Params.Send[out].WetGain; \
144
frac = *DataPosFrac; \
145
OutPos -= BufferSize; \
149
value = sampler(data+pos, 1, frac); \
151
value = lpFilter2PC(WetFilter, 0, value); \
152
WetClickRemoval[0] -= value*WetSend; \
154
for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
156
/* First order interpolator */ \
157
value = sampler(data+pos, 1, frac); \
159
/* Room path final mix buffer and panning */ \
160
value = lpFilter2P(WetFilter, 0, value); \
161
WetBuffer[OutPos] += value*WetSend; \
164
pos += frac>>FRACTIONBITS; \
165
frac &= FRACTIONMASK; \
168
if(OutPos == SamplesToDo) \
170
value = sampler(data+pos, 1, frac); \
172
value = lpFilter2PC(WetFilter, 0, value); \
173
WetPendingClicks[0] += value*WetSend; \
176
*DataPosInt += pos; \
177
*DataPosFrac = frac; \
180
DECL_TEMPLATE(ALfloat, point32)
181
DECL_TEMPLATE(ALfloat, lerp32)
182
DECL_TEMPLATE(ALfloat, cubic32)
184
DECL_TEMPLATE(ALshort, point16)
185
DECL_TEMPLATE(ALshort, lerp16)
186
DECL_TEMPLATE(ALshort, cubic16)
188
DECL_TEMPLATE(ALubyte, point8)
189
DECL_TEMPLATE(ALubyte, lerp8)
190
DECL_TEMPLATE(ALubyte, cubic8)
195
#define DECL_TEMPLATE(T, chnct, sampler) \
196
static void Mix_##T##_##chnct##_##sampler(ALsource *Source, ALCdevice *Device,\
197
const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
198
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
200
const ALuint Channels = chnct; \
201
const ALfloat scaler = 1.0f/chnct; \
202
ALfloat (*DryBuffer)[MAXCHANNELS]; \
203
ALfloat *ClickRemoval, *PendingClicks; \
205
ALfloat DrySend[chnct][MAXCHANNELS]; \
212
increment = Source->Params.Step; \
214
DryBuffer = Device->DryBuffer; \
215
ClickRemoval = Device->ClickRemoval; \
216
PendingClicks = Device->PendingClicks; \
217
DryFilter = &Source->Params.iirFilter; \
218
for(i = 0;i < Channels;i++) \
220
for(c = 0;c < MAXCHANNELS;c++) \
221
DrySend[i][c] = Source->Params.DryGains[i][c]; \
225
frac = *DataPosFrac; \
229
for(i = 0;i < Channels;i++) \
231
value = sampler(data + pos*Channels + i, Channels, frac); \
233
value = lpFilter2PC(DryFilter, i*2, value); \
234
for(c = 0;c < MAXCHANNELS;c++) \
235
ClickRemoval[c] -= value*DrySend[i][c]; \
238
for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
240
for(i = 0;i < Channels;i++) \
242
value = sampler(data + pos*Channels + i, Channels, frac); \
244
value = lpFilter2P(DryFilter, i*2, value); \
245
for(c = 0;c < MAXCHANNELS;c++) \
246
DryBuffer[OutPos][c] += value*DrySend[i][c]; \
250
pos += frac>>FRACTIONBITS; \
251
frac &= FRACTIONMASK; \
254
if(OutPos == SamplesToDo) \
256
for(i = 0;i < Channels;i++) \
258
value = sampler(data + pos*Channels + i, Channels, frac); \
260
value = lpFilter2PC(DryFilter, i*2, value); \
261
for(c = 0;c < MAXCHANNELS;c++) \
262
PendingClicks[c] += value*DrySend[i][c]; \
266
for(out = 0;out < Device->NumAuxSends;out++) \
269
ALfloat *WetBuffer; \
270
ALfloat *WetClickRemoval; \
271
ALfloat *WetPendingClicks; \
274
if(!Source->Send[out].Slot || \
275
Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
278
WetBuffer = Source->Send[out].Slot->WetBuffer; \
279
WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
280
WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
281
WetFilter = &Source->Params.Send[out].iirFilter; \
282
WetSend = Source->Params.Send[out].WetGain; \
285
frac = *DataPosFrac; \
286
OutPos -= BufferSize; \
290
for(i = 0;i < Channels;i++) \
292
value = sampler(data + pos*Channels + i, Channels, frac); \
294
value = lpFilter1PC(WetFilter, i, value); \
295
WetClickRemoval[0] -= value*WetSend * scaler; \
298
for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
300
for(i = 0;i < Channels;i++) \
302
value = sampler(data + pos*Channels + i, Channels, frac); \
304
value = lpFilter1P(WetFilter, i, value); \
305
WetBuffer[OutPos] += value*WetSend * scaler; \
309
pos += frac>>FRACTIONBITS; \
310
frac &= FRACTIONMASK; \
313
if(OutPos == SamplesToDo) \
315
for(i = 0;i < Channels;i++) \
317
value = sampler(data + pos*Channels + i, Channels, frac); \
319
value = lpFilter1PC(WetFilter, i, value); \
320
WetPendingClicks[0] += value*WetSend * scaler; \
324
*DataPosInt += pos; \
325
*DataPosFrac = frac; \
328
DECL_TEMPLATE(ALfloat, 2, point32)
329
DECL_TEMPLATE(ALfloat, 2, lerp32)
330
DECL_TEMPLATE(ALfloat, 2, cubic32)
332
DECL_TEMPLATE(ALshort, 2, point16)
333
DECL_TEMPLATE(ALshort, 2, lerp16)
334
DECL_TEMPLATE(ALshort, 2, cubic16)
336
DECL_TEMPLATE(ALubyte, 2, point8)
337
DECL_TEMPLATE(ALubyte, 2, lerp8)
338
DECL_TEMPLATE(ALubyte, 2, cubic8)
341
DECL_TEMPLATE(ALfloat, 4, point32)
342
DECL_TEMPLATE(ALfloat, 4, lerp32)
343
DECL_TEMPLATE(ALfloat, 4, cubic32)
345
DECL_TEMPLATE(ALshort, 4, point16)
346
DECL_TEMPLATE(ALshort, 4, lerp16)
347
DECL_TEMPLATE(ALshort, 4, cubic16)
349
DECL_TEMPLATE(ALubyte, 4, point8)
350
DECL_TEMPLATE(ALubyte, 4, lerp8)
351
DECL_TEMPLATE(ALubyte, 4, cubic8)
354
DECL_TEMPLATE(ALfloat, 6, point32)
355
DECL_TEMPLATE(ALfloat, 6, lerp32)
356
DECL_TEMPLATE(ALfloat, 6, cubic32)
358
DECL_TEMPLATE(ALshort, 6, point16)
359
DECL_TEMPLATE(ALshort, 6, lerp16)
360
DECL_TEMPLATE(ALshort, 6, cubic16)
362
DECL_TEMPLATE(ALubyte, 6, point8)
363
DECL_TEMPLATE(ALubyte, 6, lerp8)
364
DECL_TEMPLATE(ALubyte, 6, cubic8)
367
DECL_TEMPLATE(ALfloat, 7, point32)
368
DECL_TEMPLATE(ALfloat, 7, lerp32)
369
DECL_TEMPLATE(ALfloat, 7, cubic32)
371
DECL_TEMPLATE(ALshort, 7, point16)
372
DECL_TEMPLATE(ALshort, 7, lerp16)
373
DECL_TEMPLATE(ALshort, 7, cubic16)
375
DECL_TEMPLATE(ALubyte, 7, point8)
376
DECL_TEMPLATE(ALubyte, 7, lerp8)
377
DECL_TEMPLATE(ALubyte, 7, cubic8)
380
DECL_TEMPLATE(ALfloat, 8, point32)
381
DECL_TEMPLATE(ALfloat, 8, lerp32)
382
DECL_TEMPLATE(ALfloat, 8, cubic32)
384
DECL_TEMPLATE(ALshort, 8, point16)
385
DECL_TEMPLATE(ALshort, 8, lerp16)
386
DECL_TEMPLATE(ALshort, 8, cubic16)
388
DECL_TEMPLATE(ALubyte, 8, point8)
389
DECL_TEMPLATE(ALubyte, 8, lerp8)
390
DECL_TEMPLATE(ALubyte, 8, cubic8)
395
#define DECL_TEMPLATE(T, sampler) \
396
static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
397
enum FmtChannels FmtChannels, \
398
const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
399
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
401
switch(FmtChannels) \
404
Mix_##T##_1_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
405
OutPos, SamplesToDo, BufferSize); \
409
Mix_##T##_2_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
410
OutPos, SamplesToDo, BufferSize); \
413
Mix_##T##_4_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
414
OutPos, SamplesToDo, BufferSize); \
417
Mix_##T##_6_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
418
OutPos, SamplesToDo, BufferSize); \
421
Mix_##T##_7_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
422
OutPos, SamplesToDo, BufferSize); \
425
Mix_##T##_8_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
426
OutPos, SamplesToDo, BufferSize); \
431
DECL_TEMPLATE(ALfloat, point32)
432
DECL_TEMPLATE(ALfloat, lerp32)
433
DECL_TEMPLATE(ALfloat, cubic32)
435
DECL_TEMPLATE(ALshort, point16)
436
DECL_TEMPLATE(ALshort, lerp16)
437
DECL_TEMPLATE(ALshort, cubic16)
439
DECL_TEMPLATE(ALubyte, point8)
440
DECL_TEMPLATE(ALubyte, lerp8)
441
DECL_TEMPLATE(ALubyte, cubic8)
446
#define DECL_TEMPLATE(sampler) \
447
static void Mix_##sampler(ALsource *Source, ALCdevice *Device, \
448
enum FmtChannels FmtChannels, enum FmtType FmtType, \
449
const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
450
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
455
Mix_ALubyte_##sampler##8(Source, Device, FmtChannels, \
456
Data, DataPosInt, DataPosFrac, \
457
OutPos, SamplesToDo, BufferSize); \
461
Mix_ALshort_##sampler##16(Source, Device, FmtChannels, \
462
Data, DataPosInt, DataPosFrac, \
463
OutPos, SamplesToDo, BufferSize); \
467
Mix_ALfloat_##sampler##32(Source, Device, FmtChannels, \
468
Data, DataPosInt, DataPosFrac, \
469
OutPos, SamplesToDo, BufferSize); \
481
ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
483
ALbufferlistitem *BufferListItem;
484
ALuint DataPosInt, DataPosFrac;
485
enum FmtChannels FmtChannels;
486
enum FmtType FmtType;
487
ALuint BuffersPlayed;
490
resampler_t Resampler;
497
/* Get source info */
498
State = Source->state;
499
BuffersPlayed = Source->BuffersPlayed;
500
DataPosInt = Source->position;
501
DataPosFrac = Source->position_fraction;
502
Looping = Source->bLooping;
503
increment = Source->Params.Step;
504
Resampler = (increment == FRACTIONONE) ? POINT_RESAMPLER :
507
/* Get buffer info */
509
FmtChannels = FmtMono;
511
BufferListItem = Source->queue;
512
for(i = 0;i < Source->BuffersInQueue;i++)
514
const ALbuffer *ALBuffer;
515
if((ALBuffer=BufferListItem->buffer) != NULL)
517
FmtChannels = ALBuffer->FmtChannels;
518
FmtType = ALBuffer->FmtType;
519
FrameSize = FrameSizeFromFmt(FmtChannels, FmtType);
522
BufferListItem = BufferListItem->next;
525
/* Get current buffer queue item */
526
BufferListItem = Source->queue;
527
for(i = 0;i < BuffersPlayed;i++)
528
BufferListItem = BufferListItem->next;
532
const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
533
const ALuint BufferPadding = ResamplerPadding[Resampler];
534
ALubyte StackData[STACK_DATA_SIZE];
535
ALubyte *SrcData = StackData;
536
ALuint SrcDataSize = 0;
539
/* Figure out how many buffer bytes will be needed */
540
DataSize64 = SamplesToDo-OutPos+1;
541
DataSize64 *= increment;
542
DataSize64 += DataPosFrac+FRACTIONMASK;
543
DataSize64 >>= FRACTIONBITS;
544
DataSize64 += BufferPadding+BufferPrePadding;
545
DataSize64 *= FrameSize;
547
BufferSize = min(DataSize64, STACK_DATA_SIZE);
548
BufferSize -= BufferSize%FrameSize;
550
if(Source->lSourceType == AL_STATIC)
552
const ALbuffer *ALBuffer = Source->Buffer;
553
const ALubyte *Data = ALBuffer->data;
557
/* If current pos is beyond the loop range, do not loop */
558
if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
562
if(DataPosInt >= BufferPrePadding)
563
pos = (DataPosInt-BufferPrePadding)*FrameSize;
566
DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
567
DataSize = min(BufferSize, DataSize);
569
memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
570
SrcDataSize += DataSize;
571
BufferSize -= DataSize;
576
/* Copy what's left to play in the source buffer, and clear the
577
* rest of the temp buffer */
578
DataSize = ALBuffer->size - pos;
579
DataSize = min(BufferSize, DataSize);
581
memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
582
SrcDataSize += DataSize;
583
BufferSize -= DataSize;
585
memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
586
SrcDataSize += BufferSize;
587
BufferSize -= BufferSize;
591
ALuint LoopStart = ALBuffer->LoopStart;
592
ALuint LoopEnd = ALBuffer->LoopEnd;
594
if(DataPosInt >= LoopStart)
596
pos = DataPosInt-LoopStart;
597
while(pos < BufferPrePadding)
598
pos += LoopEnd-LoopStart;
599
pos -= BufferPrePadding;
603
else if(DataPosInt >= BufferPrePadding)
604
pos = (DataPosInt-BufferPrePadding)*FrameSize;
607
DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
608
DataSize = min(BufferSize, DataSize);
610
memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
611
SrcDataSize += DataSize;
612
BufferSize -= DataSize;
617
/* Copy what's left of this loop iteration, then copy repeats
618
* of the loop section */
619
DataSize = LoopEnd*FrameSize - pos;
620
DataSize = min(BufferSize, DataSize);
622
memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
623
SrcDataSize += DataSize;
624
BufferSize -= DataSize;
626
DataSize = (LoopEnd-LoopStart) * FrameSize;
627
while(BufferSize > 0)
629
DataSize = min(BufferSize, DataSize);
631
memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
632
SrcDataSize += DataSize;
633
BufferSize -= DataSize;
639
/* Crawl the buffer queue to fill in the temp buffer */
640
ALbufferlistitem *BufferListIter = BufferListItem;
643
if(DataPosInt >= BufferPrePadding)
644
pos = (DataPosInt-BufferPrePadding)*FrameSize;
647
pos = (BufferPrePadding-DataPosInt)*FrameSize;
650
if(!BufferListIter->prev && !Looping)
652
ALuint DataSize = min(BufferSize, pos);
654
memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
655
SrcDataSize += DataSize;
656
BufferSize -= DataSize;
662
if(BufferListIter->prev)
663
BufferListIter = BufferListIter->prev;
666
while(BufferListIter->next)
667
BufferListIter = BufferListIter->next;
670
if(BufferListIter->buffer)
672
if((ALuint)BufferListIter->buffer->size > pos)
674
pos = BufferListIter->buffer->size - pos;
677
pos -= BufferListIter->buffer->size;
682
while(BufferListIter && BufferSize > 0)
684
const ALbuffer *ALBuffer;
685
if((ALBuffer=BufferListIter->buffer) != NULL)
687
const ALubyte *Data = ALBuffer->data;
688
ALuint DataSize = ALBuffer->size;
690
/* Skip the data already played */
699
DataSize = min(BufferSize, DataSize);
700
memcpy(&SrcData[SrcDataSize], Data, DataSize);
701
SrcDataSize += DataSize;
702
BufferSize -= DataSize;
705
BufferListIter = BufferListIter->next;
706
if(!BufferListIter && Looping)
707
BufferListIter = Source->queue;
708
else if(!BufferListIter)
710
memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
711
SrcDataSize += BufferSize;
712
BufferSize -= BufferSize;
717
/* Figure out how many samples we can mix. */
718
DataSize64 = SrcDataSize / FrameSize;
719
DataSize64 -= BufferPadding+BufferPrePadding;
720
DataSize64 <<= FRACTIONBITS;
721
DataSize64 -= increment;
722
DataSize64 -= DataPosFrac;
724
BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
725
BufferSize = min(BufferSize, (SamplesToDo-OutPos));
727
SrcData += BufferPrePadding*FrameSize;
730
case POINT_RESAMPLER:
731
Mix_point(Source, Device, FmtChannels, FmtType,
732
SrcData, &DataPosInt, &DataPosFrac,
733
OutPos, SamplesToDo, BufferSize);
735
case LINEAR_RESAMPLER:
736
Mix_lerp(Source, Device, FmtChannels, FmtType,
737
SrcData, &DataPosInt, &DataPosFrac,
738
OutPos, SamplesToDo, BufferSize);
740
case CUBIC_RESAMPLER:
741
Mix_cubic(Source, Device, FmtChannels, FmtType,
742
SrcData, &DataPosInt, &DataPosFrac,
743
OutPos, SamplesToDo, BufferSize);
749
OutPos += BufferSize;
751
/* Handle looping sources */
754
const ALbuffer *ALBuffer;
756
ALuint LoopStart = 0;
759
if((ALBuffer=BufferListItem->buffer) != NULL)
761
DataSize = ALBuffer->size / FrameSize;
762
LoopStart = ALBuffer->LoopStart;
763
LoopEnd = ALBuffer->LoopEnd;
764
if(LoopEnd > DataPosInt)
768
if(Looping && Source->lSourceType == AL_STATIC)
770
BufferListItem = Source->queue;
771
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
775
if(DataSize > DataPosInt)
778
if(BufferListItem->next)
780
BufferListItem = BufferListItem->next;
785
BufferListItem = Source->queue;
791
BufferListItem = Source->queue;
792
BuffersPlayed = Source->BuffersInQueue;
798
DataPosInt -= DataSize;
800
} while(State == AL_PLAYING && OutPos < SamplesToDo);
802
/* Update source info */
803
Source->state = State;
804
Source->BuffersPlayed = BuffersPlayed;
805
Source->position = DataPosInt;
806
Source->position_fraction = DataPosFrac;
807
Source->Buffer = BufferListItem->buffer;