Move aluMixData back to ALu.c
[openal-soft.git] / Alc / mixer.c
blobbd73899cf5d580c27c4951debbdefffdc263886f
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 return val1 + ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
50 static __inline ALfloat cos_lerp32(ALfloat val1, ALfloat val2, ALint frac)
52 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
53 return val1 + ((val2-val1)*mult);
56 static __inline ALfloat point16(ALfloat val1, ALfloat val2, ALint frac)
58 return val1 / 32767.0f;
59 (void)val2;
60 (void)frac;
62 static __inline ALfloat lerp16(ALfloat val1, ALfloat val2, ALint frac)
64 val1 += ((val2-val1)*(frac * (1.0f/(1<<FRACTIONBITS))));
65 return val1 / 32767.0f;
67 static __inline ALfloat cos_lerp16(ALfloat val1, ALfloat val2, ALint frac)
69 ALfloat mult = (1.0f-cos(frac * (1.0f/(1<<FRACTIONBITS)) * M_PI)) * 0.5f;
70 val1 += ((val2-val1)*mult);
71 return val1 / 32767.0f;
75 #define DO_MIX_MONO(S,sampler) do { \
76 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
77 ALfloat *ClickRemoval, *PendingClicks; \
78 ALuint pos = DataPosInt; \
79 ALuint frac = DataPosFrac; \
80 ALfloat DrySend[OUTPUTCHANNELS]; \
81 FILTER *DryFilter; \
82 ALuint BufferIdx; \
83 ALuint i, out; \
84 ALfloat value; \
86 DryBuffer = Device->DryBuffer; \
87 ClickRemoval = Device->ClickRemoval; \
88 PendingClicks = Device->PendingClicks; \
89 DryFilter = &Source->Params.iirFilter; \
90 for(i = 0;i < OUTPUTCHANNELS;i++) \
91 DrySend[i] = Source->Params.DryGains[i]; \
93 if(j == 0) \
94 { \
95 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
97 value = lpFilter4PC(DryFilter, 0, value); \
98 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
99 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
100 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
101 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
102 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
103 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
104 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
105 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
107 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
109 /* First order interpolator */ \
110 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
112 /* Direct path final mix buffer and panning */ \
113 value = lpFilter4P(DryFilter, 0, value); \
114 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
115 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
116 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
117 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
118 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
119 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
120 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
121 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
123 frac += increment; \
124 pos += frac>>FRACTIONBITS; \
125 frac &= FRACTIONMASK; \
126 j++; \
128 if(j == SamplesToDo) \
130 ALuint p = pos; \
131 ALuint f = frac; \
132 if(p >= LoopEnd) \
134 ALuint64 pos64 = pos; \
135 pos64 <<= FRACTIONBITS; \
136 pos64 += frac; \
137 pos64 -= increment; \
138 p = pos64>>FRACTIONBITS; \
139 f = pos64&FRACTIONMASK; \
141 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
143 value = lpFilter4PC(DryFilter, 0, value); \
144 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
145 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
146 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
147 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
148 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
149 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
150 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
151 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
154 for(out = 0;out < Device->NumAuxSends;out++) \
156 ALfloat WetSend; \
157 ALfloat *WetBuffer; \
158 ALfloat *WetClickRemoval; \
159 ALfloat *WetPendingClicks; \
160 FILTER *WetFilter; \
162 if(!Source->Send[out].Slot || \
163 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
164 continue; \
166 WetSend = Source->Params.WetGains[out]; \
167 WetBuffer = Source->Send[out].Slot->WetBuffer; \
168 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
169 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
170 WetFilter = &Source->Params.Send[out].iirFilter; \
172 pos = DataPosInt; \
173 frac = DataPosFrac; \
174 j -= BufferSize; \
176 if(j == 0) \
178 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
180 value = lpFilter2PC(WetFilter, 0, value); \
181 WetClickRemoval[0] -= value*WetSend; \
183 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
185 /* First order interpolator */ \
186 value = sampler##S(Data.p##S[pos], Data.p##S[pos+1], frac); \
188 /* Room path final mix buffer and panning */ \
189 value = lpFilter2P(WetFilter, 0, value); \
190 WetBuffer[j] += value*WetSend; \
192 frac += increment; \
193 pos += frac>>FRACTIONBITS; \
194 frac &= FRACTIONMASK; \
195 j++; \
197 if(j == SamplesToDo) \
199 ALuint p = pos; \
200 ALuint f = frac; \
201 if(p >= LoopEnd) \
203 ALuint64 pos64 = pos; \
204 pos64 <<= FRACTIONBITS; \
205 pos64 += frac; \
206 pos64 -= increment; \
207 p = pos64>>FRACTIONBITS; \
208 f = pos64&FRACTIONMASK; \
210 value = sampler##S(Data.p##S[p], Data.p##S[p+1], f); \
212 value = lpFilter2PC(WetFilter, 0, value); \
213 WetPendingClicks[0] += value*WetSend; \
216 DataPosInt = pos; \
217 DataPosFrac = frac; \
218 } while(0)
220 #define DO_MIX_STEREO(S,sampler) do { \
221 const ALfloat scaler = 1.0f/Channels; \
222 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
223 ALfloat *ClickRemoval, *PendingClicks; \
224 ALuint pos = DataPosInt; \
225 ALuint frac = DataPosFrac; \
226 ALfloat DrySend[OUTPUTCHANNELS]; \
227 FILTER *DryFilter; \
228 ALuint BufferIdx; \
229 ALuint i, out; \
230 ALfloat value; \
232 DryBuffer = Device->DryBuffer; \
233 ClickRemoval = Device->ClickRemoval; \
234 PendingClicks = Device->PendingClicks; \
235 DryFilter = &Source->Params.iirFilter; \
236 for(i = 0;i < OUTPUTCHANNELS;i++) \
237 DrySend[i] = Source->Params.DryGains[i]; \
239 if(j == 0) \
241 for(i = 0;i < Channels;i++) \
243 value = sampler##S(Data.p##S[pos*Channels + i], \
244 Data.p##S[(pos+1)*Channels + i], frac); \
246 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
247 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
248 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
249 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
252 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
254 for(i = 0;i < Channels;i++) \
256 value = sampler##S(Data.p##S[pos*Channels + i], \
257 Data.p##S[(pos+1)*Channels + i], frac); \
259 value = lpFilter2P(DryFilter, chans[i]*2, value); \
260 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
261 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
262 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
265 frac += increment; \
266 pos += frac>>FRACTIONBITS; \
267 frac &= FRACTIONMASK; \
268 j++; \
270 if(j == SamplesToDo) \
272 ALuint p = pos; \
273 ALuint f = frac; \
274 if(p >= LoopEnd) \
276 ALuint64 pos64 = pos; \
277 pos64 <<= FRACTIONBITS; \
278 pos64 += frac; \
279 pos64 -= increment; \
280 p = pos64>>FRACTIONBITS; \
281 f = pos64&FRACTIONMASK; \
283 for(i = 0;i < Channels;i++) \
285 value = sampler##S(Data.p##S[p*Channels + i], \
286 Data.p##S[(p+1)*Channels + i], f); \
288 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
289 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
290 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
291 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
295 for(out = 0;out < Device->NumAuxSends;out++) \
297 ALfloat WetSend; \
298 ALfloat *WetBuffer; \
299 ALfloat *WetClickRemoval; \
300 ALfloat *WetPendingClicks; \
301 FILTER *WetFilter; \
303 if(!Source->Send[out].Slot || \
304 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
305 continue; \
307 WetSend = Source->Params.WetGains[out]; \
308 WetBuffer = Source->Send[out].Slot->WetBuffer; \
309 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
310 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
311 WetFilter = &Source->Params.Send[out].iirFilter; \
313 pos = DataPosInt; \
314 frac = DataPosFrac; \
315 j -= BufferSize; \
317 if(j == 0) \
319 for(i = 0;i < Channels;i++) \
321 value = sampler##S(Data.p##S[pos*Channels + i], \
322 Data.p##S[(pos+1)*Channels + i], frac); \
324 value = lpFilter1PC(WetFilter, chans[i], value); \
325 WetClickRemoval[0] -= value*WetSend * scaler; \
328 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
330 for(i = 0;i < Channels;i++) \
332 value = sampler##S(Data.p##S[pos*Channels + i], \
333 Data.p##S[(pos+1)*Channels + i], frac); \
335 value = lpFilter1P(WetFilter, chans[i], value); \
336 WetBuffer[j] += value*WetSend * scaler; \
339 frac += increment; \
340 pos += frac>>FRACTIONBITS; \
341 frac &= FRACTIONMASK; \
342 j++; \
344 if(j == SamplesToDo) \
346 ALuint p = pos; \
347 ALuint f = frac; \
348 if(p >= LoopEnd) \
350 ALuint64 pos64 = pos; \
351 pos64 <<= FRACTIONBITS; \
352 pos64 += frac; \
353 pos64 -= increment; \
354 p = pos64>>FRACTIONBITS; \
355 f = pos64&FRACTIONMASK; \
357 for(i = 0;i < Channels;i++) \
359 value = sampler##S(Data.p##S[p*Channels + i], \
360 Data.p##S[(p+1)*Channels + i], f); \
362 value = lpFilter1PC(WetFilter, chans[i], value); \
363 WetPendingClicks[0] += value*WetSend * scaler; \
367 DataPosInt = pos; \
368 DataPosFrac = frac; \
369 } while(0)
371 #define DO_MIX_MC(S,sampler) do { \
372 const ALfloat scaler = 1.0f/Channels; \
373 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
374 ALfloat *ClickRemoval, *PendingClicks; \
375 ALuint pos = DataPosInt; \
376 ALuint frac = DataPosFrac; \
377 ALfloat DrySend[OUTPUTCHANNELS]; \
378 FILTER *DryFilter; \
379 ALuint BufferIdx; \
380 ALuint i, out; \
381 ALfloat value; \
383 DryBuffer = Device->DryBuffer; \
384 ClickRemoval = Device->ClickRemoval; \
385 PendingClicks = Device->PendingClicks; \
386 DryFilter = &Source->Params.iirFilter; \
387 for(i = 0;i < OUTPUTCHANNELS;i++) \
388 DrySend[i] = Source->Params.DryGains[i]; \
390 if(j == 0) \
392 for(i = 0;i < Channels;i++) \
394 value = sampler##S(Data.p##S[pos*Channels + i], \
395 Data.p##S[(pos+1)*Channels + i], frac); \
397 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
398 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
401 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
403 for(i = 0;i < Channels;i++) \
405 value = sampler##S(Data.p##S[pos*Channels + i], \
406 Data.p##S[(pos+1)*Channels + i], frac); \
408 value = lpFilter2P(DryFilter, chans[i]*2, value); \
409 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
412 frac += increment; \
413 pos += frac>>FRACTIONBITS; \
414 frac &= FRACTIONMASK; \
415 j++; \
417 if(j == SamplesToDo) \
419 ALuint p = pos; \
420 ALuint f = frac; \
421 if(p >= LoopEnd) \
423 ALuint64 pos64 = pos; \
424 pos64 <<= FRACTIONBITS; \
425 pos64 += frac; \
426 pos64 -= increment; \
427 p = pos64>>FRACTIONBITS; \
428 f = pos64&FRACTIONMASK; \
430 for(i = 0;i < Channels;i++) \
432 value = sampler##S(Data.p##S[p*Channels + i], \
433 Data.p##S[(p+1)*Channels + i], f); \
435 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
436 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
440 for(out = 0;out < Device->NumAuxSends;out++) \
442 ALfloat WetSend; \
443 ALfloat *WetBuffer; \
444 ALfloat *WetClickRemoval; \
445 ALfloat *WetPendingClicks; \
446 FILTER *WetFilter; \
448 if(!Source->Send[out].Slot || \
449 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
450 continue; \
452 WetBuffer = Source->Send[out].Slot->WetBuffer; \
453 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
454 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
455 WetFilter = &Source->Params.Send[out].iirFilter; \
456 WetSend = Source->Params.WetGains[out]; \
458 pos = DataPosInt; \
459 frac = DataPosFrac; \
460 j -= BufferSize; \
462 if(j == 0) \
464 for(i = 0;i < Channels;i++) \
466 value = sampler##S(Data.p##S[pos*Channels + i], \
467 Data.p##S[(pos+1)*Channels + i], frac); \
469 value = lpFilter1PC(WetFilter, chans[i], value); \
470 WetClickRemoval[0] -= value*WetSend * scaler; \
473 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
475 for(i = 0;i < Channels;i++) \
477 value = sampler##S(Data.p##S[pos*Channels + i], \
478 Data.p##S[(pos+1)*Channels + i], frac); \
480 value = lpFilter1P(WetFilter, chans[i], value); \
481 WetBuffer[j] += value*WetSend * scaler; \
484 frac += increment; \
485 pos += frac>>FRACTIONBITS; \
486 frac &= FRACTIONMASK; \
487 j++; \
489 if(j == SamplesToDo) \
491 ALuint p = pos; \
492 ALuint f = frac; \
493 if(p >= LoopEnd) \
495 ALuint64 pos64 = pos; \
496 pos64 <<= FRACTIONBITS; \
497 pos64 += frac; \
498 pos64 -= increment; \
499 p = pos64>>FRACTIONBITS; \
500 f = pos64&FRACTIONMASK; \
502 for(i = 0;i < Channels;i++) \
504 value = sampler##S(Data.p##S[p*Channels + i], \
505 Data.p##S[(p+1)*Channels + i], f); \
507 value = lpFilter1PC(WetFilter, chans[i], value); \
508 WetPendingClicks[0] += value*WetSend * scaler; \
512 DataPosInt = pos; \
513 DataPosFrac = frac; \
514 } while(0)
517 #define MIX_MONO(sampler) do { \
518 if(Bytes == 4) \
519 DO_MIX_MONO(32,sampler); \
520 else if(Bytes == 2) \
521 DO_MIX_MONO(16,sampler); \
522 } while(0)
524 #define MIX_STEREO(sampler) do { \
525 const int chans[] = { \
526 FRONT_LEFT, FRONT_RIGHT, \
527 SIDE_LEFT, SIDE_RIGHT, \
528 BACK_LEFT, BACK_RIGHT \
529 }; \
531 if(Bytes == 4) \
532 DO_MIX_STEREO(32,sampler); \
533 else if(Bytes == 2) \
534 DO_MIX_STEREO(16,sampler); \
535 } while(0)
537 #define MIX_MC(sampler,...) do { \
538 const int chans[] = { __VA_ARGS__ }; \
540 if(Bytes == 4) \
541 DO_MIX_MC(32,sampler); \
542 else if(Bytes == 2) \
543 DO_MIX_MC(16,sampler); \
544 } while(0)
547 #define MIX(sampler) do { \
548 switch(Channels) \
550 case 1: /* Mono */ \
551 MIX_MONO(sampler); \
552 break; \
553 case 2: /* Stereo */ \
554 MIX_STEREO(sampler); \
555 break; \
556 case 4: /* Quad */ \
557 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
558 BACK_LEFT, BACK_RIGHT); \
559 break; \
560 case 6: /* 5.1 */ \
561 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
562 FRONT_CENTER, LFE, \
563 BACK_LEFT, BACK_RIGHT); \
564 break; \
565 case 7: /* 6.1 */ \
566 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
567 FRONT_CENTER, LFE, \
568 BACK_CENTER, \
569 SIDE_LEFT, SIDE_RIGHT); \
570 break; \
571 case 8: /* 7.1 */ \
572 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
573 FRONT_CENTER, LFE, \
574 BACK_LEFT, BACK_RIGHT, \
575 SIDE_LEFT, SIDE_RIGHT); \
576 break; \
578 } while(0)
581 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
583 ALbufferlistitem *BufferListItem;
584 ALint64 DataSize64,DataPos64;
585 ALint increment;
586 ALuint DataPosInt, DataPosFrac;
587 ALuint BuffersPlayed;
588 ALboolean Looping;
589 ALenum State;
590 ALuint i, j;
592 /* Get source info */
593 State = Source->state;
594 BuffersPlayed = Source->BuffersPlayed;
595 DataPosInt = Source->position;
596 DataPosFrac = Source->position_fraction;
597 Looping = Source->bLooping;
599 /* Get current buffer queue item */
600 BufferListItem = Source->queue;
601 for(i = 0;i < BuffersPlayed;i++)
602 BufferListItem = BufferListItem->next;
604 j = 0;
605 do {
606 const ALbuffer *ALBuffer;
607 union {
608 ALfloat *p32;
609 ALshort *p16;
610 ALubyte *p8;
611 } Data = { NULL };
612 ALuint DataSize = 0;
613 ALuint LoopStart = 0;
614 ALuint LoopEnd = 0;
615 ALuint Channels, Bytes;
616 ALuint BufferSize;
618 /* Get buffer info */
619 if((ALBuffer=BufferListItem->buffer) != NULL)
621 Data.p8 = ALBuffer->data;
622 DataSize = ALBuffer->size;
623 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
624 Channels = aluChannelsFromFormat(ALBuffer->format);
625 Bytes = aluBytesFromFormat(ALBuffer->format);
627 LoopStart = 0;
628 LoopEnd = DataSize;
629 if(Looping && Source->lSourceType == AL_STATIC)
631 /* If current pos is beyond the loop range, do not loop */
632 if(DataPosInt >= LoopEnd)
633 Looping = AL_FALSE;
634 else
636 LoopStart = ALBuffer->LoopStart;
637 LoopEnd = ALBuffer->LoopEnd;
642 if(DataPosInt >= DataSize)
643 goto skipmix;
645 if(BufferListItem->next)
647 ALbuffer *NextBuf = BufferListItem->next->buffer;
648 if(NextBuf && NextBuf->size)
650 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
651 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
652 memcpy(&Data.p8[DataSize*Channels*Bytes],
653 NextBuf->data, ulExtraSamples);
656 else if(Looping)
658 ALbuffer *NextBuf = Source->queue->buffer;
659 if(NextBuf && NextBuf->size)
661 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
662 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
663 memcpy(&Data.p8[DataSize*Channels*Bytes],
664 &((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes],
665 ulExtraSamples);
668 else
669 memset(&Data.p8[DataSize*Channels*Bytes], 0, (BUFFER_PADDING*Channels*Bytes));
671 /* Figure out how many samples we can mix. */
672 increment = Source->Params.Step;
673 DataSize64 = LoopEnd;
674 DataSize64 <<= FRACTIONBITS;
675 DataPos64 = DataPosInt;
676 DataPos64 <<= FRACTIONBITS;
677 DataPos64 += DataPosFrac;
678 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
680 BufferSize = min(BufferSize, (SamplesToDo-j));
682 switch(Source->Resampler)
684 case POINT_RESAMPLER:
685 MIX(point); break;
686 case LINEAR_RESAMPLER:
687 MIX(lerp); break;
688 case COSINE_RESAMPLER:
689 MIX(cos_lerp); break;
690 case RESAMPLER_MIN:
691 case RESAMPLER_MAX:
692 break;
695 skipmix:
696 /* Handle looping sources */
697 if(DataPosInt >= LoopEnd)
699 if(BufferListItem->next)
701 BufferListItem = BufferListItem->next;
702 BuffersPlayed++;
703 DataPosInt -= DataSize;
705 else if(Looping)
707 BufferListItem = Source->queue;
708 BuffersPlayed = 0;
709 if(Source->lSourceType == AL_STATIC)
710 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
711 else
712 DataPosInt -= DataSize;
714 else
716 State = AL_STOPPED;
717 BufferListItem = Source->queue;
718 BuffersPlayed = Source->BuffersInQueue;
719 DataPosInt = 0;
720 DataPosFrac = 0;
723 } while(State == AL_PLAYING && j < SamplesToDo);
725 /* Update source info */
726 Source->state = State;
727 Source->BuffersPlayed = BuffersPlayed;
728 Source->position = DataPosInt;
729 Source->position_fraction = DataPosFrac;
730 Source->Buffer = BufferListItem->buffer;