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
point(ALdouble val1
, ALdouble val2
, ALint frac
)
46 static __inline ALdouble
lerp(ALdouble val1
, ALdouble val2
, ALint frac
)
48 val1
+= ((val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
))));
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; }
64 #define DECL_MIX_MONO(T,sampler) \
65 static void Mix_##T##_Mono_##sampler(ALsource *Source, ALCdevice *Device, \
66 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
67 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
69 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
70 ALfloat *ClickRemoval, *PendingClicks; \
72 ALfloat DrySend[OUTPUTCHANNELS]; \
79 increment = Source->Params.Step; \
81 DryBuffer = Device->DryBuffer; \
82 ClickRemoval = Device->ClickRemoval; \
83 PendingClicks = Device->PendingClicks; \
84 DryFilter = &Source->Params.iirFilter; \
85 for(i = 0;i < OUTPUTCHANNELS;i++) \
86 DrySend[i] = Source->Params.DryGains[i]; \
89 frac = *DataPosFrac; \
93 value = sampler(data[pos], data[pos+1], frac); \
95 value = lpFilter4PC(DryFilter, 0, value); \
96 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
97 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
98 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
99 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
100 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
101 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
102 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
103 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
105 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
107 /* First order interpolator */ \
108 value = sampler(data[pos], data[pos+1], frac); \
110 /* Direct path final mix buffer and panning */ \
111 value = lpFilter4P(DryFilter, 0, value); \
112 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
113 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
114 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
115 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
116 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
117 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
118 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
119 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
122 pos += frac>>FRACTIONBITS; \
123 frac &= FRACTIONMASK; \
126 if(j == SamplesToDo) \
128 value = sampler(data[pos], data[pos+1], frac); \
130 value = lpFilter4PC(DryFilter, 0, value); \
131 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
132 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
133 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
134 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
135 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
136 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
137 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
138 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
141 for(out = 0;out < Device->NumAuxSends;out++) \
144 ALfloat *WetBuffer; \
145 ALfloat *WetClickRemoval; \
146 ALfloat *WetPendingClicks; \
149 if(!Source->Send[out].Slot || \
150 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
153 WetBuffer = Source->Send[out].Slot->WetBuffer; \
154 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
155 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
156 WetFilter = &Source->Params.Send[out].iirFilter; \
157 WetSend = Source->Params.Send[out].WetGain; \
160 frac = *DataPosFrac; \
165 value = sampler(data[pos], data[pos+1], frac); \
167 value = lpFilter2PC(WetFilter, 0, value); \
168 WetClickRemoval[0] -= value*WetSend; \
170 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
172 /* First order interpolator */ \
173 value = sampler(data[pos], data[pos+1], frac); \
175 /* Room path final mix buffer and panning */ \
176 value = lpFilter2P(WetFilter, 0, value); \
177 WetBuffer[j] += value*WetSend; \
180 pos += frac>>FRACTIONBITS; \
181 frac &= FRACTIONMASK; \
184 if(j == SamplesToDo) \
186 value = sampler(data[pos], data[pos+1], frac); \
188 value = lpFilter2PC(WetFilter, 0, value); \
189 WetPendingClicks[0] += value*WetSend; \
192 *DataPosInt += pos; \
193 *DataPosFrac = frac; \
196 DECL_MIX_MONO(ALfloat
, point
)
197 DECL_MIX_MONO(ALfloat
, lerp
)
199 DECL_MIX_MONO(ALshort
, point16
)
200 DECL_MIX_MONO(ALshort
, lerp16
)
202 DECL_MIX_MONO(ALubyte
, point8
)
203 DECL_MIX_MONO(ALubyte
, lerp8
)
206 #define DECL_MIX_STEREO(T,sampler) \
207 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
208 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
209 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
211 static const ALuint Channels = 2; \
212 static const Channel chans[] = { \
213 FRONT_LEFT, FRONT_RIGHT, \
214 SIDE_LEFT, SIDE_RIGHT, \
215 BACK_LEFT, BACK_RIGHT \
217 const ALfloat scaler = 1.0f/Channels; \
218 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
219 ALfloat *ClickRemoval, *PendingClicks; \
221 ALfloat DrySend[OUTPUTCHANNELS]; \
228 increment = Source->Params.Step; \
230 DryBuffer = Device->DryBuffer; \
231 ClickRemoval = Device->ClickRemoval; \
232 PendingClicks = Device->PendingClicks; \
233 DryFilter = &Source->Params.iirFilter; \
234 for(i = 0;i < OUTPUTCHANNELS;i++) \
235 DrySend[i] = Source->Params.DryGains[i]; \
238 frac = *DataPosFrac; \
242 for(i = 0;i < Channels;i++) \
244 value = sampler(data[pos*Channels + i], \
245 data[(pos+1)*Channels + i], frac); \
247 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
248 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
249 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
250 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
253 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
255 for(i = 0;i < Channels;i++) \
257 value = sampler(data[pos*Channels + i], \
258 data[(pos+1)*Channels + i], frac); \
260 value = lpFilter2P(DryFilter, chans[i]*2, value); \
261 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
262 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
263 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
267 pos += frac>>FRACTIONBITS; \
268 frac &= FRACTIONMASK; \
271 if(j == SamplesToDo) \
273 for(i = 0;i < Channels;i++) \
275 value = sampler(data[pos*Channels + i], \
276 data[(pos+1)*Channels + i], frac); \
278 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
279 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
280 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
281 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
285 for(out = 0;out < Device->NumAuxSends;out++) \
288 ALfloat *WetBuffer; \
289 ALfloat *WetClickRemoval; \
290 ALfloat *WetPendingClicks; \
293 if(!Source->Send[out].Slot || \
294 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
297 WetBuffer = Source->Send[out].Slot->WetBuffer; \
298 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
299 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
300 WetFilter = &Source->Params.Send[out].iirFilter; \
301 WetSend = Source->Params.Send[out].WetGain; \
304 frac = *DataPosFrac; \
309 for(i = 0;i < Channels;i++) \
311 value = sampler(data[pos*Channels + i], \
312 data[(pos+1)*Channels + i], frac); \
314 value = lpFilter1PC(WetFilter, chans[i], value); \
315 WetClickRemoval[0] -= value*WetSend * scaler; \
318 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
320 for(i = 0;i < Channels;i++) \
322 value = sampler(data[pos*Channels + i], \
323 data[(pos+1)*Channels + i], frac); \
325 value = lpFilter1P(WetFilter, chans[i], value); \
326 WetBuffer[j] += value*WetSend * scaler; \
330 pos += frac>>FRACTIONBITS; \
331 frac &= FRACTIONMASK; \
334 if(j == SamplesToDo) \
336 for(i = 0;i < Channels;i++) \
338 value = sampler(data[pos*Channels + i], \
339 data[(pos+1)*Channels + i], frac); \
341 value = lpFilter1PC(WetFilter, chans[i], value); \
342 WetPendingClicks[0] += value*WetSend * scaler; \
346 *DataPosInt += pos; \
347 *DataPosFrac = frac; \
350 DECL_MIX_STEREO(ALfloat
, point
)
351 DECL_MIX_STEREO(ALfloat
, lerp
)
353 DECL_MIX_STEREO(ALshort
, point16
)
354 DECL_MIX_STEREO(ALshort
, lerp16
)
356 DECL_MIX_STEREO(ALubyte
, point8
)
357 DECL_MIX_STEREO(ALubyte
, lerp8
)
360 #define DECL_MIX_MC(T,chans,sampler) \
361 static void Mix_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
362 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
363 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
365 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
366 const ALfloat scaler = 1.0f/Channels; \
367 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
368 ALfloat *ClickRemoval, *PendingClicks; \
370 ALfloat DrySend[OUTPUTCHANNELS]; \
377 increment = Source->Params.Step; \
379 DryBuffer = Device->DryBuffer; \
380 ClickRemoval = Device->ClickRemoval; \
381 PendingClicks = Device->PendingClicks; \
382 DryFilter = &Source->Params.iirFilter; \
383 for(i = 0;i < OUTPUTCHANNELS;i++) \
384 DrySend[i] = Source->Params.DryGains[i]; \
387 frac = *DataPosFrac; \
391 for(i = 0;i < Channels;i++) \
393 value = sampler(data[pos*Channels + i], \
394 data[(pos+1)*Channels + i], frac); \
396 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
397 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
400 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
402 for(i = 0;i < Channels;i++) \
404 value = sampler(data[pos*Channels + i], \
405 data[(pos+1)*Channels + i], frac); \
407 value = lpFilter2P(DryFilter, chans[i]*2, value); \
408 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
412 pos += frac>>FRACTIONBITS; \
413 frac &= FRACTIONMASK; \
416 if(j == SamplesToDo) \
418 for(i = 0;i < Channels;i++) \
420 value = sampler(data[pos*Channels + i], \
421 data[(pos+1)*Channels + i], frac); \
423 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
424 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
428 for(out = 0;out < Device->NumAuxSends;out++) \
431 ALfloat *WetBuffer; \
432 ALfloat *WetClickRemoval; \
433 ALfloat *WetPendingClicks; \
436 if(!Source->Send[out].Slot || \
437 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
440 WetBuffer = Source->Send[out].Slot->WetBuffer; \
441 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
442 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
443 WetFilter = &Source->Params.Send[out].iirFilter; \
444 WetSend = Source->Params.Send[out].WetGain; \
447 frac = *DataPosFrac; \
452 for(i = 0;i < Channels;i++) \
454 value = sampler(data[pos*Channels + i], \
455 data[(pos+1)*Channels + i], frac); \
457 value = lpFilter1PC(WetFilter, chans[i], value); \
458 WetClickRemoval[0] -= value*WetSend * scaler; \
461 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
463 for(i = 0;i < Channels;i++) \
465 value = sampler(data[pos*Channels + i], \
466 data[(pos+1)*Channels + i], frac); \
468 value = lpFilter1P(WetFilter, chans[i], value); \
469 WetBuffer[j] += value*WetSend * scaler; \
473 pos += frac>>FRACTIONBITS; \
474 frac &= FRACTIONMASK; \
477 if(j == SamplesToDo) \
479 for(i = 0;i < Channels;i++) \
481 value = sampler(data[pos*Channels + i], \
482 data[(pos+1)*Channels + i], frac); \
484 value = lpFilter1PC(WetFilter, chans[i], value); \
485 WetPendingClicks[0] += value*WetSend * scaler; \
489 *DataPosInt += pos; \
490 *DataPosFrac = frac; \
493 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
494 BACK_LEFT
, BACK_RIGHT
};
495 DECL_MIX_MC(ALfloat
, QuadChans
, point
)
496 DECL_MIX_MC(ALfloat
, QuadChans
, lerp
)
498 DECL_MIX_MC(ALshort
, QuadChans
, point16
)
499 DECL_MIX_MC(ALshort
, QuadChans
, lerp16
)
501 DECL_MIX_MC(ALubyte
, QuadChans
, point8
)
502 DECL_MIX_MC(ALubyte
, QuadChans
, lerp8
)
505 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
507 BACK_LEFT
, BACK_RIGHT
};
508 DECL_MIX_MC(ALfloat
, X51Chans
, point
)
509 DECL_MIX_MC(ALfloat
, X51Chans
, lerp
)
511 DECL_MIX_MC(ALshort
, X51Chans
, point16
)
512 DECL_MIX_MC(ALshort
, X51Chans
, lerp16
)
514 DECL_MIX_MC(ALubyte
, X51Chans
, point8
)
515 DECL_MIX_MC(ALubyte
, X51Chans
, lerp8
)
518 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
521 SIDE_LEFT
, SIDE_RIGHT
};
522 DECL_MIX_MC(ALfloat
, X61Chans
, point
)
523 DECL_MIX_MC(ALfloat
, X61Chans
, lerp
)
525 DECL_MIX_MC(ALshort
, X61Chans
, point16
)
526 DECL_MIX_MC(ALshort
, X61Chans
, lerp16
)
528 DECL_MIX_MC(ALubyte
, X61Chans
, point8
)
529 DECL_MIX_MC(ALubyte
, X61Chans
, lerp8
)
532 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
534 BACK_LEFT
, BACK_RIGHT
,
535 SIDE_LEFT
, SIDE_RIGHT
};
536 DECL_MIX_MC(ALfloat
, X71Chans
, point
)
537 DECL_MIX_MC(ALfloat
, X71Chans
, lerp
)
539 DECL_MIX_MC(ALshort
, X71Chans
, point16
)
540 DECL_MIX_MC(ALshort
, X71Chans
, lerp16
)
542 DECL_MIX_MC(ALubyte
, X71Chans
, point8
)
543 DECL_MIX_MC(ALubyte
, X71Chans
, lerp8
)
546 #define DECL_MIX(T, sampler) \
547 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
548 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
549 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
554 Mix_##T##_Mono_##sampler(Source, Device, \
555 Data, DataPosInt, DataPosFrac, \
556 j, SamplesToDo, BufferSize); \
558 case 2: /* Stereo */ \
559 Mix_##T##_Stereo_##sampler(Source, Device, \
560 Data, DataPosInt, DataPosFrac, \
561 j, SamplesToDo, BufferSize); \
564 Mix_##T##_QuadChans_##sampler(Source, Device, \
565 Data, DataPosInt, DataPosFrac, \
566 j, SamplesToDo, BufferSize); \
569 Mix_##T##_X51Chans_##sampler(Source, Device, \
570 Data, DataPosInt, DataPosFrac, \
571 j, SamplesToDo, BufferSize); \
574 Mix_##T##_X61Chans_##sampler(Source, Device, \
575 Data, DataPosInt, DataPosFrac, \
576 j, SamplesToDo, BufferSize); \
579 Mix_##T##_X71Chans_##sampler(Source, Device, \
580 Data, DataPosInt, DataPosFrac, \
581 j, SamplesToDo, BufferSize); \
586 DECL_MIX(ALfloat
, point
)
587 DECL_MIX(ALfloat
, lerp
)
589 DECL_MIX(ALshort
, point16
)
590 DECL_MIX(ALshort
, lerp16
)
592 DECL_MIX(ALubyte
, point8
)
593 DECL_MIX(ALubyte
, lerp8
)
596 /* Stack data size can be whatever. Larger values need more stack, while
597 * smaller values may need more iterations */
598 #ifndef STACK_DATA_SIZE
599 #define STACK_DATA_SIZE 16384
602 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
604 ALbufferlistitem
*BufferListItem
;
605 ALuint FrameSize
, Channels
, Bytes
;
606 ALuint DataPosInt
, DataPosFrac
;
607 ALuint BuffersPlayed
;
614 /* Get source info */
615 State
= Source
->state
;
616 BuffersPlayed
= Source
->BuffersPlayed
;
617 DataPosInt
= Source
->position
;
618 DataPosFrac
= Source
->position_fraction
;
619 Looping
= Source
->bLooping
;
620 increment
= Source
->Params
.Step
;
622 /* Get buffer info */
623 FrameSize
= Channels
= Bytes
= 0;
624 BufferListItem
= Source
->queue
;
625 for(i
= 0;i
< Source
->BuffersInQueue
;i
++)
627 const ALbuffer
*ALBuffer
;
628 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
630 FrameSize
= aluFrameSizeFromFormat(ALBuffer
->format
);
631 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
632 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
635 BufferListItem
= BufferListItem
->next
;
638 /* Get current buffer queue item */
639 BufferListItem
= Source
->queue
;
640 for(i
= 0;i
< BuffersPlayed
;i
++)
641 BufferListItem
= BufferListItem
->next
;
645 ALubyte SrcData
[STACK_DATA_SIZE
];
646 ALuint SrcDataSize
= 0;
649 /* Figure out how many buffer bytes will be needed */
650 DataSize64
= SamplesToDo
-j
+1;
651 DataSize64
*= increment
;
652 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
653 DataSize64
>>= FRACTIONBITS
;
654 DataSize64
+= BUFFER_PADDING
;
655 DataSize64
*= FrameSize
;
657 BufferSize
= sizeof(SrcData
) - SrcDataSize
;
658 BufferSize
= min(DataSize64
, BufferSize
);
660 if(Source
->lSourceType
== AL_STATIC
)
662 const ALbuffer
*ALBuffer
= Source
->Buffer
;
663 const ALubyte
*Data
= ALBuffer
->data
;
666 /* If current pos is beyond the loop range, do not loop */
667 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
671 /* Copy what's left to play in the source buffer, and clear the
672 * rest of the temp buffer */
673 DataSize
= ALBuffer
->size
- DataPosInt
*FrameSize
;
674 DataSize
= min(BufferSize
, DataSize
);
676 memcpy(&SrcData
[SrcDataSize
], &Data
[DataPosInt
*FrameSize
], DataSize
);
677 SrcDataSize
+= DataSize
;
678 BufferSize
-= DataSize
;
680 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
681 SrcDataSize
+= BufferSize
;
682 BufferSize
-= BufferSize
;
686 ALuint LoopStart
= ALBuffer
->LoopStart
;
687 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
689 /* Copy what's left of this loop iteration, then copy repeats
690 * of the loop section */
691 DataSize
= (LoopEnd
-DataPosInt
) * FrameSize
;
692 DataSize
= min(BufferSize
, DataSize
);
694 memcpy(&SrcData
[SrcDataSize
], &Data
[DataPosInt
*FrameSize
], DataSize
);
695 SrcDataSize
+= DataSize
;
696 BufferSize
-= DataSize
;
698 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
699 while(BufferSize
> 0)
701 DataSize
= min(BufferSize
, DataSize
);
703 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
704 SrcDataSize
+= DataSize
;
705 BufferSize
-= DataSize
;
711 /* Crawl the buffer queue to fill in the temp buffer */
712 ALbufferlistitem
*BufferListIter
= BufferListItem
;
713 ALuint pos
= DataPosInt
*FrameSize
;
715 while(BufferListIter
&& BufferSize
> 0)
717 const ALbuffer
*ALBuffer
;
718 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
720 const ALubyte
*Data
= ALBuffer
->data
;
721 ALuint DataSize
= ALBuffer
->size
;
723 /* Skip the data already played */
732 DataSize
= min(BufferSize
, DataSize
);
733 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
734 SrcDataSize
+= DataSize
;
735 BufferSize
-= DataSize
;
738 BufferListIter
= BufferListIter
->next
;
739 if(!BufferListIter
&& Looping
)
740 BufferListIter
= Source
->queue
;
741 else if(!BufferListIter
)
743 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
744 SrcDataSize
+= BufferSize
;
745 BufferSize
-= BufferSize
;
750 /* Figure out how many samples we can mix. */
751 DataSize64
= SrcDataSize
/ FrameSize
;
752 DataSize64
-= BUFFER_PADDING
;
753 DataSize64
<<= FRACTIONBITS
;
754 DataSize64
-= increment
;
756 BufferSize
= (ALuint
)((DataSize64
-DataPosFrac
+(increment
-1)) / increment
);
757 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
760 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
761 increment
, increment
/(double)(1<<FRACTIONBITS
));
763 BufferListItem
= Source
->queue
;
764 BuffersPlayed
= Source
->BuffersInQueue
;
770 switch(Source
->Resampler
)
772 case POINT_RESAMPLER
:
774 Mix_ALfloat_point(Source
, Device
, Channels
,
775 SrcData
, &DataPosInt
, &DataPosFrac
,
776 j
, SamplesToDo
, BufferSize
);
778 Mix_ALshort_point16(Source
, Device
, Channels
,
779 SrcData
, &DataPosInt
, &DataPosFrac
,
780 j
, SamplesToDo
, BufferSize
);
782 Mix_ALubyte_point8(Source
, Device
, Channels
,
783 SrcData
, &DataPosInt
, &DataPosFrac
,
784 j
, SamplesToDo
, BufferSize
);
786 case LINEAR_RESAMPLER
:
788 Mix_ALfloat_lerp(Source
, Device
, Channels
,
789 SrcData
, &DataPosInt
, &DataPosFrac
,
790 j
, SamplesToDo
, BufferSize
);
792 Mix_ALshort_lerp16(Source
, Device
, Channels
,
793 SrcData
, &DataPosInt
, &DataPosFrac
,
794 j
, SamplesToDo
, BufferSize
);
796 Mix_ALubyte_lerp8(Source
, Device
, Channels
,
797 SrcData
, &DataPosInt
, &DataPosFrac
,
798 j
, SamplesToDo
, BufferSize
);
806 /* Handle looping sources */
809 const ALbuffer
*ALBuffer
;
811 ALuint LoopStart
= 0;
814 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
816 DataSize
= ALBuffer
->size
/ FrameSize
;
817 if(DataSize
> DataPosInt
)
819 LoopStart
= ALBuffer
->LoopStart
;
820 LoopEnd
= ALBuffer
->LoopEnd
;
823 if(BufferListItem
->next
)
825 BufferListItem
= BufferListItem
->next
;
830 BufferListItem
= Source
->queue
;
832 if(Source
->lSourceType
== AL_STATIC
)
834 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
841 BufferListItem
= Source
->queue
;
842 BuffersPlayed
= Source
->BuffersInQueue
;
848 DataPosInt
-= DataSize
;
850 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
852 /* Update source info */
853 Source
->state
= State
;
854 Source
->BuffersPlayed
= BuffersPlayed
;
855 Source
->position
= DataPosInt
;
856 Source
->position_fraction
= DataPosFrac
;
857 Source
->Buffer
= BufferListItem
->buffer
;