Add "pre-padding" to the temp buffer
[openal-soft.git] / Alc / mixer.c
blob3c76cd40cb1032205d28430352e2ab0cb8a89d64
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 ALdouble point(ALdouble val1, ALdouble val2, ALint frac)
42 return val1;
43 (void)val2;
44 (void)frac;
46 static __inline ALdouble lerp(ALdouble val1, ALdouble val2, ALint frac)
48 val1 += ((val2-val1) * (frac * (1.0/(1<<FRACTIONBITS))));
49 return val1;
52 static __inline ALdouble point16(ALdouble val1, ALdouble val2, ALint frac)
53 { return point(val1, val2, frac) / 32767.0; }
54 static __inline ALdouble lerp16(ALdouble val1, ALdouble val2, ALint frac)
55 { return lerp(val1, val2, frac) / 32767.0; }
57 static __inline ALdouble point8(ALdouble val1, ALdouble val2, ALint frac)
58 { return (point(val1, val2, frac)-128.0) / 127.0; }
59 static __inline ALdouble lerp8(ALdouble val1, ALdouble val2, ALint frac)
60 { return (lerp(val1, val2, frac)-128.0) / 127.0; }
63 #define DECL_TEMPLATE(T, sampler) \
64 static void Mix_##T##_Mono_##sampler(ALsource *Source, ALCdevice *Device, \
65 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
66 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
67 { \
68 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
69 ALfloat *ClickRemoval, *PendingClicks; \
70 ALuint pos, frac; \
71 ALfloat DrySend[OUTPUTCHANNELS]; \
72 FILTER *DryFilter; \
73 ALuint BufferIdx; \
74 ALuint increment; \
75 ALuint i, out; \
76 ALfloat value; \
78 increment = Source->Params.Step; \
80 DryBuffer = Device->DryBuffer; \
81 ClickRemoval = Device->ClickRemoval; \
82 PendingClicks = Device->PendingClicks; \
83 DryFilter = &Source->Params.iirFilter; \
84 for(i = 0;i < OUTPUTCHANNELS;i++) \
85 DrySend[i] = Source->Params.DryGains[i]; \
87 pos = 0; \
88 frac = *DataPosFrac; \
90 if(j == 0) \
91 { \
92 value = sampler(data[pos], data[pos+1], frac); \
94 value = lpFilter4PC(DryFilter, 0, value); \
95 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
96 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
97 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
98 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
99 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
100 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
101 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
102 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
104 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
106 /* First order interpolator */ \
107 value = sampler(data[pos], data[pos+1], frac); \
109 /* Direct path final mix buffer and panning */ \
110 value = lpFilter4P(DryFilter, 0, value); \
111 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
112 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
113 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
114 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
115 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
116 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
117 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
118 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
120 frac += increment; \
121 pos += frac>>FRACTIONBITS; \
122 frac &= FRACTIONMASK; \
123 j++; \
125 if(j == SamplesToDo) \
127 value = sampler(data[pos], data[pos+1], frac); \
129 value = lpFilter4PC(DryFilter, 0, value); \
130 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
131 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
132 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
133 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
134 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
135 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
136 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
137 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
140 for(out = 0;out < Device->NumAuxSends;out++) \
142 ALfloat WetSend; \
143 ALfloat *WetBuffer; \
144 ALfloat *WetClickRemoval; \
145 ALfloat *WetPendingClicks; \
146 FILTER *WetFilter; \
148 if(!Source->Send[out].Slot || \
149 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
150 continue; \
152 WetBuffer = Source->Send[out].Slot->WetBuffer; \
153 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
154 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
155 WetFilter = &Source->Params.Send[out].iirFilter; \
156 WetSend = Source->Params.Send[out].WetGain; \
158 pos = 0; \
159 frac = *DataPosFrac; \
160 j -= BufferSize; \
162 if(j == 0) \
164 value = sampler(data[pos], data[pos+1], frac); \
166 value = lpFilter2PC(WetFilter, 0, value); \
167 WetClickRemoval[0] -= value*WetSend; \
169 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
171 /* First order interpolator */ \
172 value = sampler(data[pos], data[pos+1], frac); \
174 /* Room path final mix buffer and panning */ \
175 value = lpFilter2P(WetFilter, 0, value); \
176 WetBuffer[j] += value*WetSend; \
178 frac += increment; \
179 pos += frac>>FRACTIONBITS; \
180 frac &= FRACTIONMASK; \
181 j++; \
183 if(j == SamplesToDo) \
185 value = sampler(data[pos], data[pos+1], frac); \
187 value = lpFilter2PC(WetFilter, 0, value); \
188 WetPendingClicks[0] += value*WetSend; \
191 *DataPosInt += pos; \
192 *DataPosFrac = frac; \
195 DECL_TEMPLATE(ALfloat, point)
196 DECL_TEMPLATE(ALfloat, lerp)
198 DECL_TEMPLATE(ALshort, point16)
199 DECL_TEMPLATE(ALshort, lerp16)
201 DECL_TEMPLATE(ALubyte, point8)
202 DECL_TEMPLATE(ALubyte, lerp8)
204 #undef DECL_TEMPLATE
207 #define DECL_TEMPLATE(T, sampler) \
208 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
209 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
210 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
212 static const ALuint Channels = 2; \
213 static const Channel chans[] = { \
214 FRONT_LEFT, FRONT_RIGHT, \
215 SIDE_LEFT, SIDE_RIGHT, \
216 BACK_LEFT, BACK_RIGHT \
217 }; \
218 const ALfloat scaler = 1.0f/Channels; \
219 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
220 ALfloat *ClickRemoval, *PendingClicks; \
221 ALuint pos, frac; \
222 ALfloat DrySend[OUTPUTCHANNELS]; \
223 FILTER *DryFilter; \
224 ALuint BufferIdx; \
225 ALuint increment; \
226 ALuint i, out; \
227 ALfloat value; \
229 increment = Source->Params.Step; \
231 DryBuffer = Device->DryBuffer; \
232 ClickRemoval = Device->ClickRemoval; \
233 PendingClicks = Device->PendingClicks; \
234 DryFilter = &Source->Params.iirFilter; \
235 for(i = 0;i < OUTPUTCHANNELS;i++) \
236 DrySend[i] = Source->Params.DryGains[i]; \
238 pos = 0; \
239 frac = *DataPosFrac; \
241 if(j == 0) \
243 for(i = 0;i < Channels;i++) \
245 value = sampler(data[pos*Channels + i], \
246 data[(pos+1)*Channels + i], frac); \
248 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
249 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
250 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
251 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
254 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
256 for(i = 0;i < Channels;i++) \
258 value = sampler(data[pos*Channels + i], \
259 data[(pos+1)*Channels + i], frac); \
261 value = lpFilter2P(DryFilter, chans[i]*2, value); \
262 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
263 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
264 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
267 frac += increment; \
268 pos += frac>>FRACTIONBITS; \
269 frac &= FRACTIONMASK; \
270 j++; \
272 if(j == SamplesToDo) \
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 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
281 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
282 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
286 for(out = 0;out < Device->NumAuxSends;out++) \
288 ALfloat WetSend; \
289 ALfloat *WetBuffer; \
290 ALfloat *WetClickRemoval; \
291 ALfloat *WetPendingClicks; \
292 FILTER *WetFilter; \
294 if(!Source->Send[out].Slot || \
295 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
296 continue; \
298 WetBuffer = Source->Send[out].Slot->WetBuffer; \
299 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
300 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
301 WetFilter = &Source->Params.Send[out].iirFilter; \
302 WetSend = Source->Params.Send[out].WetGain; \
304 pos = 0; \
305 frac = *DataPosFrac; \
306 j -= BufferSize; \
308 if(j == 0) \
310 for(i = 0;i < Channels;i++) \
312 value = sampler(data[pos*Channels + i], \
313 data[(pos+1)*Channels + i], frac); \
315 value = lpFilter1PC(WetFilter, chans[i], value); \
316 WetClickRemoval[0] -= value*WetSend * scaler; \
319 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
321 for(i = 0;i < Channels;i++) \
323 value = sampler(data[pos*Channels + i], \
324 data[(pos+1)*Channels + i], frac); \
326 value = lpFilter1P(WetFilter, chans[i], value); \
327 WetBuffer[j] += value*WetSend * scaler; \
330 frac += increment; \
331 pos += frac>>FRACTIONBITS; \
332 frac &= FRACTIONMASK; \
333 j++; \
335 if(j == SamplesToDo) \
337 for(i = 0;i < Channels;i++) \
339 value = sampler(data[pos*Channels + i], \
340 data[(pos+1)*Channels + i], frac); \
342 value = lpFilter1PC(WetFilter, chans[i], value); \
343 WetPendingClicks[0] += value*WetSend * scaler; \
347 *DataPosInt += pos; \
348 *DataPosFrac = frac; \
351 DECL_TEMPLATE(ALfloat, point)
352 DECL_TEMPLATE(ALfloat, lerp)
354 DECL_TEMPLATE(ALshort, point16)
355 DECL_TEMPLATE(ALshort, lerp16)
357 DECL_TEMPLATE(ALubyte, point8)
358 DECL_TEMPLATE(ALubyte, lerp8)
360 #undef DECL_TEMPLATE
363 #define DECL_TEMPLATE(T, chans, sampler) \
364 static void Mix_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
365 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
366 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
368 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
369 const ALfloat scaler = 1.0f/Channels; \
370 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
371 ALfloat *ClickRemoval, *PendingClicks; \
372 ALuint pos, frac; \
373 ALfloat DrySend[OUTPUTCHANNELS]; \
374 FILTER *DryFilter; \
375 ALuint BufferIdx; \
376 ALuint increment; \
377 ALuint i, out; \
378 ALfloat value; \
380 increment = Source->Params.Step; \
382 DryBuffer = Device->DryBuffer; \
383 ClickRemoval = Device->ClickRemoval; \
384 PendingClicks = Device->PendingClicks; \
385 DryFilter = &Source->Params.iirFilter; \
386 for(i = 0;i < OUTPUTCHANNELS;i++) \
387 DrySend[i] = Source->Params.DryGains[i]; \
389 pos = 0; \
390 frac = *DataPosFrac; \
392 if(j == 0) \
394 for(i = 0;i < Channels;i++) \
396 value = sampler(data[pos*Channels + i], \
397 data[(pos+1)*Channels + i], frac); \
399 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
400 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
403 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
405 for(i = 0;i < Channels;i++) \
407 value = sampler(data[pos*Channels + i], \
408 data[(pos+1)*Channels + i], frac); \
410 value = lpFilter2P(DryFilter, chans[i]*2, value); \
411 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
414 frac += increment; \
415 pos += frac>>FRACTIONBITS; \
416 frac &= FRACTIONMASK; \
417 j++; \
419 if(j == SamplesToDo) \
421 for(i = 0;i < Channels;i++) \
423 value = sampler(data[pos*Channels + i], \
424 data[(pos+1)*Channels + i], frac); \
426 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
427 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
431 for(out = 0;out < Device->NumAuxSends;out++) \
433 ALfloat WetSend; \
434 ALfloat *WetBuffer; \
435 ALfloat *WetClickRemoval; \
436 ALfloat *WetPendingClicks; \
437 FILTER *WetFilter; \
439 if(!Source->Send[out].Slot || \
440 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
441 continue; \
443 WetBuffer = Source->Send[out].Slot->WetBuffer; \
444 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
445 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
446 WetFilter = &Source->Params.Send[out].iirFilter; \
447 WetSend = Source->Params.Send[out].WetGain; \
449 pos = 0; \
450 frac = *DataPosFrac; \
451 j -= BufferSize; \
453 if(j == 0) \
455 for(i = 0;i < Channels;i++) \
457 value = sampler(data[pos*Channels + i], \
458 data[(pos+1)*Channels + i], frac); \
460 value = lpFilter1PC(WetFilter, chans[i], value); \
461 WetClickRemoval[0] -= value*WetSend * scaler; \
464 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
466 for(i = 0;i < Channels;i++) \
468 value = sampler(data[pos*Channels + i], \
469 data[(pos+1)*Channels + i], frac); \
471 value = lpFilter1P(WetFilter, chans[i], value); \
472 WetBuffer[j] += value*WetSend * scaler; \
475 frac += increment; \
476 pos += frac>>FRACTIONBITS; \
477 frac &= FRACTIONMASK; \
478 j++; \
480 if(j == SamplesToDo) \
482 for(i = 0;i < Channels;i++) \
484 value = sampler(data[pos*Channels + i], \
485 data[(pos+1)*Channels + i], frac); \
487 value = lpFilter1PC(WetFilter, chans[i], value); \
488 WetPendingClicks[0] += value*WetSend * scaler; \
492 *DataPosInt += pos; \
493 *DataPosFrac = frac; \
496 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
497 BACK_LEFT, BACK_RIGHT };
498 DECL_TEMPLATE(ALfloat, QuadChans, point)
499 DECL_TEMPLATE(ALfloat, QuadChans, lerp)
501 DECL_TEMPLATE(ALshort, QuadChans, point16)
502 DECL_TEMPLATE(ALshort, QuadChans, lerp16)
504 DECL_TEMPLATE(ALubyte, QuadChans, point8)
505 DECL_TEMPLATE(ALubyte, QuadChans, lerp8)
508 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
509 FRONT_CENTER, LFE,
510 BACK_LEFT, BACK_RIGHT };
511 DECL_TEMPLATE(ALfloat, X51Chans, point)
512 DECL_TEMPLATE(ALfloat, X51Chans, lerp)
514 DECL_TEMPLATE(ALshort, X51Chans, point16)
515 DECL_TEMPLATE(ALshort, X51Chans, lerp16)
517 DECL_TEMPLATE(ALubyte, X51Chans, point8)
518 DECL_TEMPLATE(ALubyte, X51Chans, lerp8)
521 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_RIGHT,
522 FRONT_CENTER, LFE,
523 BACK_CENTER,
524 SIDE_LEFT, SIDE_RIGHT };
525 DECL_TEMPLATE(ALfloat, X61Chans, point)
526 DECL_TEMPLATE(ALfloat, X61Chans, lerp)
528 DECL_TEMPLATE(ALshort, X61Chans, point16)
529 DECL_TEMPLATE(ALshort, X61Chans, lerp16)
531 DECL_TEMPLATE(ALubyte, X61Chans, point8)
532 DECL_TEMPLATE(ALubyte, X61Chans, lerp8)
535 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
536 FRONT_CENTER, LFE,
537 BACK_LEFT, BACK_RIGHT,
538 SIDE_LEFT, SIDE_RIGHT };
539 DECL_TEMPLATE(ALfloat, X71Chans, point)
540 DECL_TEMPLATE(ALfloat, X71Chans, lerp)
542 DECL_TEMPLATE(ALshort, X71Chans, point16)
543 DECL_TEMPLATE(ALshort, X71Chans, lerp16)
545 DECL_TEMPLATE(ALubyte, X71Chans, point8)
546 DECL_TEMPLATE(ALubyte, X71Chans, lerp8)
548 #undef DECL_TEMPLATE
551 #define DECL_TEMPLATE(T, sampler) \
552 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
553 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
554 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
556 switch(Channels) \
558 case 1: /* Mono */ \
559 Mix_##T##_Mono_##sampler(Source, Device, \
560 Data, DataPosInt, DataPosFrac, \
561 j, SamplesToDo, BufferSize); \
562 break; \
563 case 2: /* Stereo */ \
564 Mix_##T##_Stereo_##sampler(Source, Device, \
565 Data, DataPosInt, DataPosFrac, \
566 j, SamplesToDo, BufferSize); \
567 break; \
568 case 4: /* Quad */ \
569 Mix_##T##_QuadChans_##sampler(Source, Device, \
570 Data, DataPosInt, DataPosFrac, \
571 j, SamplesToDo, BufferSize); \
572 break; \
573 case 6: /* 5.1 */ \
574 Mix_##T##_X51Chans_##sampler(Source, Device, \
575 Data, DataPosInt, DataPosFrac, \
576 j, SamplesToDo, BufferSize); \
577 break; \
578 case 7: /* 6.1 */ \
579 Mix_##T##_X61Chans_##sampler(Source, Device, \
580 Data, DataPosInt, DataPosFrac, \
581 j, SamplesToDo, BufferSize); \
582 break; \
583 case 8: /* 7.1 */ \
584 Mix_##T##_X71Chans_##sampler(Source, Device, \
585 Data, DataPosInt, DataPosFrac, \
586 j, SamplesToDo, BufferSize); \
587 break; \
591 DECL_TEMPLATE(ALfloat, point)
592 DECL_TEMPLATE(ALfloat, lerp)
594 DECL_TEMPLATE(ALshort, point16)
595 DECL_TEMPLATE(ALshort, lerp16)
597 DECL_TEMPLATE(ALubyte, point8)
598 DECL_TEMPLATE(ALubyte, lerp8)
600 #undef DECL_TEMPLATE
603 /* Stack data size can be whatever. Larger values need more stack, while
604 * smaller values may need more iterations */
605 #ifndef STACK_DATA_SIZE
606 #define STACK_DATA_SIZE 16384
607 #endif
609 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
611 ALbufferlistitem *BufferListItem;
612 ALuint FrameSize, Channels, Bytes;
613 ALuint DataPosInt, DataPosFrac;
614 ALuint BuffersPlayed;
615 ALboolean Looping;
616 ALuint increment;
617 ALenum State;
618 ALuint i, j;
619 ALint64 DataSize64;
621 /* Get source info */
622 State = Source->state;
623 BuffersPlayed = Source->BuffersPlayed;
624 DataPosInt = Source->position;
625 DataPosFrac = Source->position_fraction;
626 Looping = Source->bLooping;
627 increment = Source->Params.Step;
629 /* Get buffer info */
630 FrameSize = Channels = Bytes = 0;
631 BufferListItem = Source->queue;
632 for(i = 0;i < Source->BuffersInQueue;i++)
634 const ALbuffer *ALBuffer;
635 if((ALBuffer=BufferListItem->buffer) != NULL)
637 FrameSize = aluFrameSizeFromFormat(ALBuffer->format);
638 Channels = aluChannelsFromFormat(ALBuffer->format);
639 Bytes = aluBytesFromFormat(ALBuffer->format);
640 break;
642 BufferListItem = BufferListItem->next;
645 /* Get current buffer queue item */
646 BufferListItem = Source->queue;
647 for(i = 0;i < BuffersPlayed;i++)
648 BufferListItem = BufferListItem->next;
650 j = 0;
651 do {
652 ALubyte StackData[STACK_DATA_SIZE];
653 ALubyte *SrcData = StackData;
654 ALuint SrcDataSize = 0;
655 ALuint BufferSize;
657 /* Figure out how many buffer bytes will be needed */
658 DataSize64 = SamplesToDo-j+1;
659 DataSize64 *= increment;
660 DataSize64 += DataPosFrac+FRACTIONMASK;
661 DataSize64 >>= FRACTIONBITS;
662 DataSize64 += BUFFER_PADDING+BUFFER_PREPADDING;
663 DataSize64 *= FrameSize;
665 BufferSize = min(DataSize64, STACK_DATA_SIZE);
666 BufferSize -= BufferSize%FrameSize;
668 if(Source->lSourceType == AL_STATIC)
670 const ALbuffer *ALBuffer = Source->Buffer;
671 const ALubyte *Data = ALBuffer->data;
672 ALuint DataSize;
673 ALuint pos;
675 /* If current pos is beyond the loop range, do not loop */
676 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
678 Looping = AL_FALSE;
680 if(DataPosInt >= BUFFER_PREPADDING)
681 pos = (DataPosInt-BUFFER_PREPADDING)*FrameSize;
682 else
684 DataSize = (BUFFER_PREPADDING-DataPosInt)*FrameSize;
685 DataSize = min(BufferSize, DataSize);
687 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
688 SrcDataSize += DataSize;
689 BufferSize -= DataSize;
691 pos = 0;
694 /* Copy what's left to play in the source buffer, and clear the
695 * rest of the temp buffer */
696 DataSize = ALBuffer->size - pos;
697 DataSize = min(BufferSize, DataSize);
699 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
700 SrcDataSize += DataSize;
701 BufferSize -= DataSize;
703 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
704 SrcDataSize += BufferSize;
705 BufferSize -= BufferSize;
707 else
709 ALuint LoopStart = ALBuffer->LoopStart;
710 ALuint LoopEnd = ALBuffer->LoopEnd;
712 if(DataPosInt >= LoopStart)
714 pos = DataPosInt-LoopStart;
715 while(pos < BUFFER_PREPADDING)
716 pos += LoopEnd-LoopStart;
717 pos -= BUFFER_PREPADDING;
718 pos += LoopStart;
719 pos *= FrameSize;
721 else if(DataPosInt >= BUFFER_PREPADDING)
722 pos = (DataPosInt-BUFFER_PREPADDING)*FrameSize;
723 else
725 DataSize = (BUFFER_PREPADDING-DataPosInt)*FrameSize;
726 DataSize = min(BufferSize, DataSize);
728 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
729 SrcDataSize += DataSize;
730 BufferSize -= DataSize;
732 pos = 0;
735 /* Copy what's left of this loop iteration, then copy repeats
736 * of the loop section */
737 DataSize = LoopEnd*FrameSize - pos;
738 DataSize = min(BufferSize, DataSize);
740 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
741 SrcDataSize += DataSize;
742 BufferSize -= DataSize;
744 DataSize = (LoopEnd-LoopStart) * FrameSize;
745 while(BufferSize > 0)
747 DataSize = min(BufferSize, DataSize);
749 memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
750 SrcDataSize += DataSize;
751 BufferSize -= DataSize;
755 else
757 /* Crawl the buffer queue to fill in the temp buffer */
758 ALbufferlistitem *BufferListIter = BufferListItem;
759 ALuint pos;
761 if(DataPosInt >= BUFFER_PREPADDING)
762 pos = (DataPosInt-BUFFER_PREPADDING)*FrameSize;
763 else
765 pos = (BUFFER_PREPADDING-DataPosInt)*FrameSize;
766 while(pos > 0)
768 if(!BufferListIter->prev && !Looping)
770 ALuint DataSize = min(BufferSize, pos);
772 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
773 SrcDataSize += DataSize;
774 BufferSize -= DataSize;
776 pos = 0;
777 break;
780 if(Looping)
782 while(BufferListIter->next)
783 BufferListIter = BufferListIter->next;
785 else
786 BufferListIter = BufferListIter->prev;
788 if(BufferListIter->buffer)
790 if((ALuint)BufferListIter->buffer->size > pos)
792 pos = BufferListIter->buffer->size - pos;
793 break;
795 pos -= BufferListIter->buffer->size;
800 while(BufferListIter && BufferSize > 0)
802 const ALbuffer *ALBuffer;
803 if((ALBuffer=BufferListIter->buffer) != NULL)
805 const ALubyte *Data = ALBuffer->data;
806 ALuint DataSize = ALBuffer->size;
808 /* Skip the data already played */
809 if(DataSize <= pos)
810 pos -= DataSize;
811 else
813 Data += pos;
814 DataSize -= pos;
815 pos -= pos;
817 DataSize = min(BufferSize, DataSize);
818 memcpy(&SrcData[SrcDataSize], Data, DataSize);
819 SrcDataSize += DataSize;
820 BufferSize -= DataSize;
823 BufferListIter = BufferListIter->next;
824 if(!BufferListIter && Looping)
825 BufferListIter = Source->queue;
826 else if(!BufferListIter)
828 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
829 SrcDataSize += BufferSize;
830 BufferSize -= BufferSize;
835 /* Figure out how many samples we can mix. */
836 DataSize64 = SrcDataSize / FrameSize;
837 DataSize64 -= BUFFER_PADDING+BUFFER_PREPADDING;
838 DataSize64 <<= FRACTIONBITS;
839 DataSize64 -= increment;
841 BufferSize = (ALuint)((DataSize64-DataPosFrac+(increment-1)) / increment);
842 BufferSize = min(BufferSize, (SamplesToDo-j));
843 if(BufferSize == 0)
845 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
846 increment, increment/(double)(1<<FRACTIONBITS));
847 State = AL_STOPPED;
848 BufferListItem = Source->queue;
849 BuffersPlayed = Source->BuffersInQueue;
850 DataPosInt = 0;
851 DataPosFrac = 0;
852 break;
855 SrcData += BUFFER_PREPADDING*FrameSize;
856 switch(Source->Resampler)
858 case POINT_RESAMPLER:
859 if(Bytes == 4)
860 Mix_ALfloat_point(Source, Device, Channels,
861 SrcData, &DataPosInt, &DataPosFrac,
862 j, SamplesToDo, BufferSize);
863 else if(Bytes == 2)
864 Mix_ALshort_point16(Source, Device, Channels,
865 SrcData, &DataPosInt, &DataPosFrac,
866 j, SamplesToDo, BufferSize);
867 else if(Bytes == 1)
868 Mix_ALubyte_point8(Source, Device, Channels,
869 SrcData, &DataPosInt, &DataPosFrac,
870 j, SamplesToDo, BufferSize);
871 break;
872 case LINEAR_RESAMPLER:
873 if(Bytes == 4)
874 Mix_ALfloat_lerp(Source, Device, Channels,
875 SrcData, &DataPosInt, &DataPosFrac,
876 j, SamplesToDo, BufferSize);
877 else if(Bytes == 2)
878 Mix_ALshort_lerp16(Source, Device, Channels,
879 SrcData, &DataPosInt, &DataPosFrac,
880 j, SamplesToDo, BufferSize);
881 else if(Bytes == 1)
882 Mix_ALubyte_lerp8(Source, Device, Channels,
883 SrcData, &DataPosInt, &DataPosFrac,
884 j, SamplesToDo, BufferSize);
885 break;
886 case RESAMPLER_MIN:
887 case RESAMPLER_MAX:
888 break;
890 j += BufferSize;
892 /* Handle looping sources */
893 while(1)
895 const ALbuffer *ALBuffer;
896 ALuint DataSize = 0;
897 ALuint LoopStart = 0;
898 ALuint LoopEnd = 0;
900 if((ALBuffer=BufferListItem->buffer) != NULL)
902 DataSize = ALBuffer->size / FrameSize;
903 if(DataSize > DataPosInt)
904 break;
905 LoopStart = ALBuffer->LoopStart;
906 LoopEnd = ALBuffer->LoopEnd;
909 if(BufferListItem->next)
911 BufferListItem = BufferListItem->next;
912 BuffersPlayed++;
914 else if(Looping)
916 BufferListItem = Source->queue;
917 BuffersPlayed = 0;
918 if(Source->lSourceType == AL_STATIC)
920 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
921 break;
924 else
926 State = AL_STOPPED;
927 BufferListItem = Source->queue;
928 BuffersPlayed = Source->BuffersInQueue;
929 DataPosInt = 0;
930 DataPosFrac = 0;
931 break;
934 DataPosInt -= DataSize;
936 } while(State == AL_PLAYING && j < SamplesToDo);
938 /* Update source info */
939 Source->state = State;
940 Source->BuffersPlayed = BuffersPlayed;
941 Source->position = DataPosInt;
942 Source->position_fraction = DataPosFrac;
943 Source->Buffer = BufferListItem->buffer;