Set mixer sample pos and frac when needed
[openal-soft.git] / Alc / mixer.c
blob7f64bad9469a5e13f6a334319836ce7de4aa9fa1
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>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.h"
40 static __inline ALfloat point32(ALfloat val1, ALfloat val2, ALint frac)
42 return val1;
43 (void)val2;
44 (void)frac;
46 static __inline ALfloat lerp32(ALfloat val1, ALfloat val2, ALint frac)
48 val1 += ((val2-val1) * (frac * (1.0/(1<<FRACTIONBITS))));
49 return val1;
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));
54 return val1;
57 static __inline ALfloat point16(ALfloat val1, ALfloat val2, ALint frac)
59 return val1 / 32767.0f;
60 (void)val2;
61 (void)frac;
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 DO_MIX_MONO(data,sampler) do { \
76 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
77 ALfloat *ClickRemoval, *PendingClicks; \
78 ALuint pos, frac; \
79 ALfloat DrySend[OUTPUTCHANNELS]; \
80 FILTER *DryFilter; \
81 ALuint BufferIdx; \
82 ALuint i, out; \
83 ALfloat value; \
85 DryBuffer = Device->DryBuffer; \
86 ClickRemoval = Device->ClickRemoval; \
87 PendingClicks = Device->PendingClicks; \
88 DryFilter = &Source->Params.iirFilter; \
89 for(i = 0;i < OUTPUTCHANNELS;i++) \
90 DrySend[i] = Source->Params.DryGains[i]; \
92 pos = DataPosInt; \
93 frac = DataPosFrac; \
95 if(j == 0) \
96 { \
97 value = sampler(data[pos], data[pos+1], frac); \
99 value = lpFilter4PC(DryFilter, 0, value); \
100 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
101 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
102 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
103 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
104 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
105 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
106 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
107 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
109 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
111 /* First order interpolator */ \
112 value = sampler(data[pos], data[pos+1], frac); \
114 /* Direct path final mix buffer and panning */ \
115 value = lpFilter4P(DryFilter, 0, value); \
116 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
117 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
118 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
119 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
120 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
121 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
122 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
123 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
125 frac += increment; \
126 pos += frac>>FRACTIONBITS; \
127 frac &= FRACTIONMASK; \
128 j++; \
130 if(j == SamplesToDo) \
132 ALuint p = pos; \
133 ALuint f = frac; \
134 if(p >= LoopEnd) \
136 ALuint64 pos64 = pos; \
137 pos64 <<= FRACTIONBITS; \
138 pos64 += frac; \
139 pos64 -= increment; \
140 p = pos64>>FRACTIONBITS; \
141 f = pos64&FRACTIONMASK; \
143 value = sampler(data[p], data[p+1], f); \
145 value = lpFilter4PC(DryFilter, 0, value); \
146 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
147 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
148 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
149 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
150 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
151 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
152 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
153 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
156 for(out = 0;out < Device->NumAuxSends;out++) \
158 ALfloat WetSend; \
159 ALfloat *WetBuffer; \
160 ALfloat *WetClickRemoval; \
161 ALfloat *WetPendingClicks; \
162 FILTER *WetFilter; \
164 if(!Source->Send[out].Slot || \
165 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
166 continue; \
168 WetBuffer = Source->Send[out].Slot->WetBuffer; \
169 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
170 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
171 WetFilter = &Source->Params.Send[out].iirFilter; \
172 WetSend = Source->Params.Send[out].WetGain; \
174 pos = DataPosInt; \
175 frac = DataPosFrac; \
176 j -= BufferSize; \
178 if(j == 0) \
180 value = sampler(data[pos], data[pos+1], frac); \
182 value = lpFilter2PC(WetFilter, 0, value); \
183 WetClickRemoval[0] -= value*WetSend; \
185 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
187 /* First order interpolator */ \
188 value = sampler(data[pos], data[pos+1], frac); \
190 /* Room path final mix buffer and panning */ \
191 value = lpFilter2P(WetFilter, 0, value); \
192 WetBuffer[j] += value*WetSend; \
194 frac += increment; \
195 pos += frac>>FRACTIONBITS; \
196 frac &= FRACTIONMASK; \
197 j++; \
199 if(j == SamplesToDo) \
201 ALuint p = pos; \
202 ALuint f = frac; \
203 if(p >= LoopEnd) \
205 ALuint64 pos64 = pos; \
206 pos64 <<= FRACTIONBITS; \
207 pos64 += frac; \
208 pos64 -= increment; \
209 p = pos64>>FRACTIONBITS; \
210 f = pos64&FRACTIONMASK; \
212 value = sampler(data[p], data[p+1], f); \
214 value = lpFilter2PC(WetFilter, 0, value); \
215 WetPendingClicks[0] += value*WetSend; \
218 DataPosInt = pos; \
219 DataPosFrac = frac; \
220 } while(0)
222 #define DO_MIX_STEREO(data,sampler) do { \
223 const ALfloat scaler = 1.0f/Channels; \
224 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
225 ALfloat *ClickRemoval, *PendingClicks; \
226 ALuint pos, frac; \
227 ALfloat DrySend[OUTPUTCHANNELS]; \
228 FILTER *DryFilter; \
229 ALuint BufferIdx; \
230 ALuint i, out; \
231 ALfloat value; \
233 DryBuffer = Device->DryBuffer; \
234 ClickRemoval = Device->ClickRemoval; \
235 PendingClicks = Device->PendingClicks; \
236 DryFilter = &Source->Params.iirFilter; \
237 for(i = 0;i < OUTPUTCHANNELS;i++) \
238 DrySend[i] = Source->Params.DryGains[i]; \
240 pos = DataPosInt; \
241 frac = DataPosFrac; \
243 if(j == 0) \
245 for(i = 0;i < Channels;i++) \
247 value = sampler(data[pos*Channels + i], \
248 data[(pos+1)*Channels + i], frac); \
250 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
251 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
252 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
253 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
256 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
258 for(i = 0;i < Channels;i++) \
260 value = sampler(data[pos*Channels + i], \
261 data[(pos+1)*Channels + i], frac); \
263 value = lpFilter2P(DryFilter, chans[i]*2, value); \
264 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
265 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
266 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
269 frac += increment; \
270 pos += frac>>FRACTIONBITS; \
271 frac &= FRACTIONMASK; \
272 j++; \
274 if(j == SamplesToDo) \
276 ALuint p = pos; \
277 ALuint f = frac; \
278 if(p >= LoopEnd) \
280 ALuint64 pos64 = pos; \
281 pos64 <<= FRACTIONBITS; \
282 pos64 += frac; \
283 pos64 -= increment; \
284 p = pos64>>FRACTIONBITS; \
285 f = pos64&FRACTIONMASK; \
287 for(i = 0;i < Channels;i++) \
289 value = sampler(data[p*Channels + i], \
290 data[(p+1)*Channels + i], f); \
292 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
293 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
294 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
295 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
299 for(out = 0;out < Device->NumAuxSends;out++) \
301 ALfloat WetSend; \
302 ALfloat *WetBuffer; \
303 ALfloat *WetClickRemoval; \
304 ALfloat *WetPendingClicks; \
305 FILTER *WetFilter; \
307 if(!Source->Send[out].Slot || \
308 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
309 continue; \
311 WetBuffer = Source->Send[out].Slot->WetBuffer; \
312 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
313 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
314 WetFilter = &Source->Params.Send[out].iirFilter; \
315 WetSend = Source->Params.Send[out].WetGain; \
317 pos = DataPosInt; \
318 frac = DataPosFrac; \
319 j -= BufferSize; \
321 if(j == 0) \
323 for(i = 0;i < Channels;i++) \
325 value = sampler(data[pos*Channels + i], \
326 data[(pos+1)*Channels + i], frac); \
328 value = lpFilter1PC(WetFilter, chans[i], value); \
329 WetClickRemoval[0] -= value*WetSend * scaler; \
332 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
334 for(i = 0;i < Channels;i++) \
336 value = sampler(data[pos*Channels + i], \
337 data[(pos+1)*Channels + i], frac); \
339 value = lpFilter1P(WetFilter, chans[i], value); \
340 WetBuffer[j] += value*WetSend * scaler; \
343 frac += increment; \
344 pos += frac>>FRACTIONBITS; \
345 frac &= FRACTIONMASK; \
346 j++; \
348 if(j == SamplesToDo) \
350 ALuint p = pos; \
351 ALuint f = frac; \
352 if(p >= LoopEnd) \
354 ALuint64 pos64 = pos; \
355 pos64 <<= FRACTIONBITS; \
356 pos64 += frac; \
357 pos64 -= increment; \
358 p = pos64>>FRACTIONBITS; \
359 f = pos64&FRACTIONMASK; \
361 for(i = 0;i < Channels;i++) \
363 value = sampler(data[p*Channels + i], \
364 data[(p+1)*Channels + i], f); \
366 value = lpFilter1PC(WetFilter, chans[i], value); \
367 WetPendingClicks[0] += value*WetSend * scaler; \
371 DataPosInt = pos; \
372 DataPosFrac = frac; \
373 } while(0)
375 #define DO_MIX_MC(data,sampler) do { \
376 const ALfloat scaler = 1.0f/Channels; \
377 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
378 ALfloat *ClickRemoval, *PendingClicks; \
379 ALuint pos, frac; \
380 ALfloat DrySend[OUTPUTCHANNELS]; \
381 FILTER *DryFilter; \
382 ALuint BufferIdx; \
383 ALuint i, out; \
384 ALfloat value; \
386 DryBuffer = Device->DryBuffer; \
387 ClickRemoval = Device->ClickRemoval; \
388 PendingClicks = Device->PendingClicks; \
389 DryFilter = &Source->Params.iirFilter; \
390 for(i = 0;i < OUTPUTCHANNELS;i++) \
391 DrySend[i] = Source->Params.DryGains[i]; \
393 pos = DataPosInt; \
394 frac = DataPosFrac; \
396 if(j == 0) \
398 for(i = 0;i < Channels;i++) \
400 value = sampler(data[pos*Channels + i], \
401 data[(pos+1)*Channels + i], frac); \
403 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
404 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
407 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
409 for(i = 0;i < Channels;i++) \
411 value = sampler(data[pos*Channels + i], \
412 data[(pos+1)*Channels + i], frac); \
414 value = lpFilter2P(DryFilter, chans[i]*2, value); \
415 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
418 frac += increment; \
419 pos += frac>>FRACTIONBITS; \
420 frac &= FRACTIONMASK; \
421 j++; \
423 if(j == SamplesToDo) \
425 ALuint p = pos; \
426 ALuint f = frac; \
427 if(p >= LoopEnd) \
429 ALuint64 pos64 = pos; \
430 pos64 <<= FRACTIONBITS; \
431 pos64 += frac; \
432 pos64 -= increment; \
433 p = pos64>>FRACTIONBITS; \
434 f = pos64&FRACTIONMASK; \
436 for(i = 0;i < Channels;i++) \
438 value = sampler(data[p*Channels + i], \
439 data[(p+1)*Channels + i], f); \
441 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
442 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
446 for(out = 0;out < Device->NumAuxSends;out++) \
448 ALfloat WetSend; \
449 ALfloat *WetBuffer; \
450 ALfloat *WetClickRemoval; \
451 ALfloat *WetPendingClicks; \
452 FILTER *WetFilter; \
454 if(!Source->Send[out].Slot || \
455 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
456 continue; \
458 WetBuffer = Source->Send[out].Slot->WetBuffer; \
459 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
460 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
461 WetFilter = &Source->Params.Send[out].iirFilter; \
462 WetSend = Source->Params.Send[out].WetGain; \
464 pos = DataPosInt; \
465 frac = DataPosFrac; \
466 j -= BufferSize; \
468 if(j == 0) \
470 for(i = 0;i < Channels;i++) \
472 value = sampler(data[pos*Channels + i], \
473 data[(pos+1)*Channels + i], frac); \
475 value = lpFilter1PC(WetFilter, chans[i], value); \
476 WetClickRemoval[0] -= value*WetSend * scaler; \
479 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
481 for(i = 0;i < Channels;i++) \
483 value = sampler(data[pos*Channels + i], \
484 data[(pos+1)*Channels + i], frac); \
486 value = lpFilter1P(WetFilter, chans[i], value); \
487 WetBuffer[j] += value*WetSend * scaler; \
490 frac += increment; \
491 pos += frac>>FRACTIONBITS; \
492 frac &= FRACTIONMASK; \
493 j++; \
495 if(j == SamplesToDo) \
497 ALuint p = pos; \
498 ALuint f = frac; \
499 if(p >= LoopEnd) \
501 ALuint64 pos64 = pos; \
502 pos64 <<= FRACTIONBITS; \
503 pos64 += frac; \
504 pos64 -= increment; \
505 p = pos64>>FRACTIONBITS; \
506 f = pos64&FRACTIONMASK; \
508 for(i = 0;i < Channels;i++) \
510 value = sampler(data[p*Channels + i], \
511 data[(p+1)*Channels + i], f); \
513 value = lpFilter1PC(WetFilter, chans[i], value); \
514 WetPendingClicks[0] += value*WetSend * scaler; \
518 DataPosInt = pos; \
519 DataPosFrac = frac; \
520 } while(0)
523 #define MIX_MONO(sampler) do { \
524 if(Bytes == 4) \
525 DO_MIX_MONO(Data.p32,sampler##32); \
526 else if(Bytes == 2) \
527 DO_MIX_MONO(Data.p16,sampler##16); \
528 } while(0)
530 #define MIX_STEREO(sampler) do { \
531 const int chans[] = { \
532 FRONT_LEFT, FRONT_RIGHT, \
533 SIDE_LEFT, SIDE_RIGHT, \
534 BACK_LEFT, BACK_RIGHT \
535 }; \
537 if(Bytes == 4) \
538 DO_MIX_STEREO(Data.p32,sampler##32); \
539 else if(Bytes == 2) \
540 DO_MIX_STEREO(Data.p16,sampler##16); \
541 } while(0)
543 #define MIX_MC(sampler,...) do { \
544 const int chans[] = { __VA_ARGS__ }; \
546 if(Bytes == 4) \
547 DO_MIX_MC(Data.p32,sampler##32); \
548 else if(Bytes == 2) \
549 DO_MIX_MC(Data.p16,sampler##16); \
550 } while(0)
553 #define MIX(sampler) do { \
554 switch(Channels) \
556 case 1: /* Mono */ \
557 MIX_MONO(sampler); \
558 break; \
559 case 2: /* Stereo */ \
560 MIX_STEREO(sampler); \
561 break; \
562 case 4: /* Quad */ \
563 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
564 BACK_LEFT, BACK_RIGHT); \
565 break; \
566 case 6: /* 5.1 */ \
567 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
568 FRONT_CENTER, LFE, \
569 BACK_LEFT, BACK_RIGHT); \
570 break; \
571 case 7: /* 6.1 */ \
572 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
573 FRONT_CENTER, LFE, \
574 BACK_CENTER, \
575 SIDE_LEFT, SIDE_RIGHT); \
576 break; \
577 case 8: /* 7.1 */ \
578 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
579 FRONT_CENTER, LFE, \
580 BACK_LEFT, BACK_RIGHT, \
581 SIDE_LEFT, SIDE_RIGHT); \
582 break; \
584 } while(0)
587 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
589 ALbufferlistitem *BufferListItem;
590 ALint64 DataSize64,DataPos64;
591 ALint increment;
592 ALuint DataPosInt, DataPosFrac;
593 ALuint BuffersPlayed;
594 ALboolean Looping;
595 ALenum State;
596 ALuint i, j;
598 /* Get source info */
599 State = Source->state;
600 BuffersPlayed = Source->BuffersPlayed;
601 DataPosInt = Source->position;
602 DataPosFrac = Source->position_fraction;
603 Looping = Source->bLooping;
605 /* Get current buffer queue item */
606 BufferListItem = Source->queue;
607 for(i = 0;i < BuffersPlayed;i++)
608 BufferListItem = BufferListItem->next;
610 j = 0;
611 do {
612 const ALbuffer *ALBuffer;
613 union {
614 ALfloat *p32;
615 ALshort *p16;
616 ALubyte *p8;
617 } Data = { NULL };
618 ALuint DataSize = 0;
619 ALuint LoopStart = 0;
620 ALuint LoopEnd = 0;
621 ALuint Channels, Bytes;
622 ALuint BufferSize;
624 /* Get buffer info */
625 if((ALBuffer=BufferListItem->buffer) != NULL)
627 Data.p8 = ALBuffer->data;
628 DataSize = ALBuffer->size;
629 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
630 Channels = aluChannelsFromFormat(ALBuffer->format);
631 Bytes = aluBytesFromFormat(ALBuffer->format);
633 LoopStart = 0;
634 LoopEnd = DataSize;
635 if(Looping && Source->lSourceType == AL_STATIC)
637 /* If current pos is beyond the loop range, do not loop */
638 if(DataPosInt >= LoopEnd)
639 Looping = AL_FALSE;
640 else
642 LoopStart = ALBuffer->LoopStart;
643 LoopEnd = ALBuffer->LoopEnd;
648 if(DataPosInt >= DataSize)
649 goto skipmix;
651 memset(&Data.p8[DataSize*Channels*Bytes], 0, BUFFER_PADDING*Channels*Bytes);
652 if(BufferListItem->next)
654 ALbuffer *NextBuf = BufferListItem->next->buffer;
655 if(NextBuf && NextBuf->size)
657 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
658 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
659 memcpy(&Data.p8[DataSize*Channels*Bytes],
660 NextBuf->data, ulExtraSamples);
663 else if(Looping)
665 ALbuffer *NextBuf = Source->queue->buffer;
666 if(NextBuf && NextBuf->size)
668 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
669 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
670 memcpy(&Data.p8[DataSize*Channels*Bytes],
671 &((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes],
672 ulExtraSamples);
676 /* Figure out how many samples we can mix. */
677 increment = Source->Params.Step;
678 DataSize64 = LoopEnd;
679 DataSize64 <<= FRACTIONBITS;
680 DataPos64 = DataPosInt;
681 DataPos64 <<= FRACTIONBITS;
682 DataPos64 += DataPosFrac;
683 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
685 BufferSize = min(BufferSize, (SamplesToDo-j));
687 switch(Source->Resampler)
689 case POINT_RESAMPLER:
690 MIX(point); break;
691 case LINEAR_RESAMPLER:
692 MIX(lerp); break;
693 case COSINE_RESAMPLER:
694 MIX(cos_lerp); break;
695 case RESAMPLER_MIN:
696 case RESAMPLER_MAX:
697 break;
700 skipmix:
701 /* Handle looping sources */
702 if(DataPosInt >= LoopEnd)
704 if(BufferListItem->next)
706 BufferListItem = BufferListItem->next;
707 BuffersPlayed++;
708 DataPosInt -= DataSize;
710 else if(Looping)
712 BufferListItem = Source->queue;
713 BuffersPlayed = 0;
714 if(Source->lSourceType == AL_STATIC)
715 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
716 else
717 DataPosInt -= DataSize;
719 else
721 State = AL_STOPPED;
722 BufferListItem = Source->queue;
723 BuffersPlayed = Source->BuffersInQueue;
724 DataPosInt = 0;
725 DataPosFrac = 0;
728 } while(State == AL_PLAYING && j < SamplesToDo);
730 /* Update source info */
731 Source->state = State;
732 Source->BuffersPlayed = BuffersPlayed;
733 Source->position = DataPosInt;
734 Source->position_fraction = DataPosFrac;
735 Source->Buffer = BufferListItem->buffer;