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; }
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) \
68 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
69 ALfloat *ClickRemoval, *PendingClicks; \
71 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
88 frac = *DataPosFrac; \
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]; \
121 pos += frac>>FRACTIONBITS; \
122 frac &= FRACTIONMASK; \
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++) \
143 ALfloat *WetBuffer; \
144 ALfloat *WetClickRemoval; \
145 ALfloat *WetPendingClicks; \
148 if(!Source->Send[out].Slot || \
149 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
159 frac = *DataPosFrac; \
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; \
179 pos += frac>>FRACTIONBITS; \
180 frac &= FRACTIONMASK; \
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
)
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 \
218 const ALfloat scaler = 1.0f/Channels; \
219 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
220 ALfloat *ClickRemoval, *PendingClicks; \
222 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
239 frac = *DataPosFrac; \
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]]; \
268 pos += frac>>FRACTIONBITS; \
269 frac &= FRACTIONMASK; \
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++) \
289 ALfloat *WetBuffer; \
290 ALfloat *WetClickRemoval; \
291 ALfloat *WetPendingClicks; \
294 if(!Source->Send[out].Slot || \
295 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
305 frac = *DataPosFrac; \
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; \
331 pos += frac>>FRACTIONBITS; \
332 frac &= FRACTIONMASK; \
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
)
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; \
373 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
390 frac = *DataPosFrac; \
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]]; \
415 pos += frac>>FRACTIONBITS; \
416 frac &= FRACTIONMASK; \
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++) \
434 ALfloat *WetBuffer; \
435 ALfloat *WetClickRemoval; \
436 ALfloat *WetPendingClicks; \
439 if(!Source->Send[out].Slot || \
440 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
450 frac = *DataPosFrac; \
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; \
476 pos += frac>>FRACTIONBITS; \
477 frac &= FRACTIONMASK; \
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
,
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
,
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
,
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
)
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) \
559 Mix_##T##_Mono_##sampler(Source, Device, \
560 Data, DataPosInt, DataPosFrac, \
561 j, SamplesToDo, BufferSize); \
563 case 2: /* Stereo */ \
564 Mix_##T##_Stereo_##sampler(Source, Device, \
565 Data, DataPosInt, DataPosFrac, \
566 j, SamplesToDo, BufferSize); \
569 Mix_##T##_QuadChans_##sampler(Source, Device, \
570 Data, DataPosInt, DataPosFrac, \
571 j, SamplesToDo, BufferSize); \
574 Mix_##T##_X51Chans_##sampler(Source, Device, \
575 Data, DataPosInt, DataPosFrac, \
576 j, SamplesToDo, BufferSize); \
579 Mix_##T##_X61Chans_##sampler(Source, Device, \
580 Data, DataPosInt, DataPosFrac, \
581 j, SamplesToDo, BufferSize); \
584 Mix_##T##_X71Chans_##sampler(Source, Device, \
585 Data, DataPosInt, DataPosFrac, \
586 j, SamplesToDo, BufferSize); \
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
)
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
609 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
611 ALbufferlistitem
*BufferListItem
;
612 ALuint FrameSize
, Channels
, Bytes
;
613 ALuint DataPosInt
, DataPosFrac
;
614 ALuint BuffersPlayed
;
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
);
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
;
652 ALubyte StackData
[STACK_DATA_SIZE
];
653 ALubyte
*SrcData
= StackData
;
654 ALuint SrcDataSize
= 0;
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
;
675 /* If current pos is beyond the loop range, do not loop */
676 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
680 if(DataPosInt
>= BUFFER_PREPADDING
)
681 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
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
;
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
;
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
;
721 else if(DataPosInt
>= BUFFER_PREPADDING
)
722 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
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
;
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
;
757 /* Crawl the buffer queue to fill in the temp buffer */
758 ALbufferlistitem
*BufferListIter
= BufferListItem
;
761 if(DataPosInt
>= BUFFER_PREPADDING
)
762 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
765 pos
= (BUFFER_PREPADDING
-DataPosInt
)*FrameSize
;
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
;
782 while(BufferListIter
->next
)
783 BufferListIter
= BufferListIter
->next
;
786 BufferListIter
= BufferListIter
->prev
;
788 if(BufferListIter
->buffer
)
790 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
792 pos
= BufferListIter
->buffer
->size
- pos
;
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 */
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
));
845 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
846 increment
, increment
/(double)(1<<FRACTIONBITS
));
848 BufferListItem
= Source
->queue
;
849 BuffersPlayed
= Source
->BuffersInQueue
;
855 SrcData
+= BUFFER_PREPADDING
*FrameSize
;
856 switch(Source
->Resampler
)
858 case POINT_RESAMPLER
:
860 Mix_ALfloat_point(Source
, Device
, Channels
,
861 SrcData
, &DataPosInt
, &DataPosFrac
,
862 j
, SamplesToDo
, BufferSize
);
864 Mix_ALshort_point16(Source
, Device
, Channels
,
865 SrcData
, &DataPosInt
, &DataPosFrac
,
866 j
, SamplesToDo
, BufferSize
);
868 Mix_ALubyte_point8(Source
, Device
, Channels
,
869 SrcData
, &DataPosInt
, &DataPosFrac
,
870 j
, SamplesToDo
, BufferSize
);
872 case LINEAR_RESAMPLER
:
874 Mix_ALfloat_lerp(Source
, Device
, Channels
,
875 SrcData
, &DataPosInt
, &DataPosFrac
,
876 j
, SamplesToDo
, BufferSize
);
878 Mix_ALshort_lerp16(Source
, Device
, Channels
,
879 SrcData
, &DataPosInt
, &DataPosFrac
,
880 j
, SamplesToDo
, BufferSize
);
882 Mix_ALubyte_lerp8(Source
, Device
, Channels
,
883 SrcData
, &DataPosInt
, &DataPosFrac
,
884 j
, SamplesToDo
, BufferSize
);
892 /* Handle looping sources */
895 const ALbuffer
*ALBuffer
;
897 ALuint LoopStart
= 0;
900 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
902 DataSize
= ALBuffer
->size
/ FrameSize
;
903 if(DataSize
> DataPosInt
)
905 LoopStart
= ALBuffer
->LoopStart
;
906 LoopEnd
= ALBuffer
->LoopEnd
;
909 if(BufferListItem
->next
)
911 BufferListItem
= BufferListItem
->next
;
916 BufferListItem
= Source
->queue
;
918 if(Source
->lSourceType
== AL_STATIC
)
920 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
927 BufferListItem
= Source
->queue
;
928 BuffersPlayed
= Source
->BuffersInQueue
;
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
;