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
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
41 { return vals
[0]; (void)step
; (void)frac
; }
42 static __inline ALdouble
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
43 { return lerp(vals
[0], vals
[step
], frac
* (1.0/(1<<FRACTIONBITS
))); }
44 static __inline ALdouble
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
45 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
46 frac
* (1.0/(1<<FRACTIONBITS
))); }
48 static __inline ALdouble
point16(const ALshort
*vals
, ALint step
, ALint frac
)
49 { return vals
[0] / 32767.0; (void)step
; (void)frac
; }
50 static __inline ALdouble
lerp16(const ALshort
*vals
, ALint step
, ALint frac
)
51 { return lerp(vals
[0], vals
[step
], frac
* (1.0/(1<<FRACTIONBITS
))) / 32767.0; }
52 static __inline ALdouble
cubic16(const ALshort
*vals
, ALint step
, ALint frac
)
53 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
54 frac
* (1.0/(1<<FRACTIONBITS
))) / 32767.0; }
56 static __inline ALdouble
point8(const ALubyte
*vals
, ALint step
, ALint frac
)
57 { return (vals
[0]-128.0) / 127.0; (void)step
; (void)frac
; }
58 static __inline ALdouble
lerp8(const ALubyte
*vals
, ALint step
, ALint frac
)
59 { return (lerp(vals
[0], vals
[step
], frac
* (1.0/(1<<FRACTIONBITS
)))-128.0) / 127.0; }
60 static __inline ALdouble
cubic8(const ALubyte
*vals
, ALint step
, ALint frac
)
61 { return (cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
62 frac
* (1.0/(1<<FRACTIONBITS
)))-128.0) / 127.0; }
65 #define DECL_TEMPLATE(T, sampler) \
66 static void Mix_##T##_Mono_##sampler(ALsource *Source, ALCdevice *Device, \
67 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
68 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
70 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
71 ALfloat *ClickRemoval, *PendingClicks; \
73 ALfloat DrySend[OUTPUTCHANNELS]; \
80 increment = Source->Params.Step; \
82 DryBuffer = Device->DryBuffer; \
83 ClickRemoval = Device->ClickRemoval; \
84 PendingClicks = Device->PendingClicks; \
85 DryFilter = &Source->Params.iirFilter; \
86 for(i = 0;i < OUTPUTCHANNELS;i++) \
87 DrySend[i] = Source->Params.DryGains[i]; \
90 frac = *DataPosFrac; \
94 value = sampler(data+pos, 1, frac); \
96 value = lpFilter4PC(DryFilter, 0, value); \
97 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
98 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
99 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
100 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
101 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
102 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
103 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
104 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
106 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
108 /* First order interpolator */ \
109 value = sampler(data+pos, 1, frac); \
111 /* Direct path final mix buffer and panning */ \
112 value = lpFilter4P(DryFilter, 0, value); \
113 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
114 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
115 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
116 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
117 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
118 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
119 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
120 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
123 pos += frac>>FRACTIONBITS; \
124 frac &= FRACTIONMASK; \
127 if(j == SamplesToDo) \
129 value = sampler(data+pos, 1, frac); \
131 value = lpFilter4PC(DryFilter, 0, value); \
132 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
133 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
134 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
135 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
136 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
137 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
138 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
139 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
142 for(out = 0;out < Device->NumAuxSends;out++) \
145 ALfloat *WetBuffer; \
146 ALfloat *WetClickRemoval; \
147 ALfloat *WetPendingClicks; \
150 if(!Source->Send[out].Slot || \
151 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
154 WetBuffer = Source->Send[out].Slot->WetBuffer; \
155 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
156 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
157 WetFilter = &Source->Params.Send[out].iirFilter; \
158 WetSend = Source->Params.Send[out].WetGain; \
161 frac = *DataPosFrac; \
166 value = sampler(data+pos, 1, frac); \
168 value = lpFilter2PC(WetFilter, 0, value); \
169 WetClickRemoval[0] -= value*WetSend; \
171 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
173 /* First order interpolator */ \
174 value = sampler(data+pos, 1, frac); \
176 /* Room path final mix buffer and panning */ \
177 value = lpFilter2P(WetFilter, 0, value); \
178 WetBuffer[j] += value*WetSend; \
181 pos += frac>>FRACTIONBITS; \
182 frac &= FRACTIONMASK; \
185 if(j == SamplesToDo) \
187 value = sampler(data+pos, 1, frac); \
189 value = lpFilter2PC(WetFilter, 0, value); \
190 WetPendingClicks[0] += value*WetSend; \
193 *DataPosInt += pos; \
194 *DataPosFrac = frac; \
197 DECL_TEMPLATE(ALfloat
, point32
)
198 DECL_TEMPLATE(ALfloat
, lerp32
)
199 DECL_TEMPLATE(ALfloat
, cubic32
)
201 DECL_TEMPLATE(ALshort
, point16
)
202 DECL_TEMPLATE(ALshort
, lerp16
)
203 DECL_TEMPLATE(ALshort
, cubic16
)
205 DECL_TEMPLATE(ALubyte
, point8
)
206 DECL_TEMPLATE(ALubyte
, lerp8
)
207 DECL_TEMPLATE(ALubyte
, cubic8
)
212 #define DECL_TEMPLATE(T, sampler) \
213 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
214 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
215 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
217 static const ALuint Channels = 2; \
218 static const Channel chans[] = { \
219 FRONT_LEFT, FRONT_RIGHT, \
220 SIDE_LEFT, SIDE_RIGHT, \
221 BACK_LEFT, BACK_RIGHT \
223 const ALfloat scaler = 1.0f/Channels; \
224 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
225 ALfloat *ClickRemoval, *PendingClicks; \
227 ALfloat DrySend[OUTPUTCHANNELS]; \
234 increment = Source->Params.Step; \
236 DryBuffer = Device->DryBuffer; \
237 ClickRemoval = Device->ClickRemoval; \
238 PendingClicks = Device->PendingClicks; \
239 DryFilter = &Source->Params.iirFilter; \
240 for(i = 0;i < OUTPUTCHANNELS;i++) \
241 DrySend[i] = Source->Params.DryGains[i]; \
244 frac = *DataPosFrac; \
248 for(i = 0;i < Channels;i++) \
250 value = sampler(data + pos*Channels + i, Channels, frac); \
252 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
253 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
254 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
255 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
258 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
260 for(i = 0;i < Channels;i++) \
262 value = sampler(data + pos*Channels + i, Channels, frac); \
264 value = lpFilter2P(DryFilter, chans[i]*2, value); \
265 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
266 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
267 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
271 pos += frac>>FRACTIONBITS; \
272 frac &= FRACTIONMASK; \
275 if(j == SamplesToDo) \
277 for(i = 0;i < Channels;i++) \
279 value = sampler(data + pos*Channels + i, Channels, frac); \
281 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
282 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
283 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
284 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
288 for(out = 0;out < Device->NumAuxSends;out++) \
291 ALfloat *WetBuffer; \
292 ALfloat *WetClickRemoval; \
293 ALfloat *WetPendingClicks; \
296 if(!Source->Send[out].Slot || \
297 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
300 WetBuffer = Source->Send[out].Slot->WetBuffer; \
301 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
302 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
303 WetFilter = &Source->Params.Send[out].iirFilter; \
304 WetSend = Source->Params.Send[out].WetGain; \
307 frac = *DataPosFrac; \
312 for(i = 0;i < Channels;i++) \
314 value = sampler(data + pos*Channels + i, Channels, frac); \
316 value = lpFilter1PC(WetFilter, chans[i], value); \
317 WetClickRemoval[0] -= value*WetSend * scaler; \
320 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
322 for(i = 0;i < Channels;i++) \
324 value = sampler(data + pos*Channels + i, Channels, 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, Channels, frac); \
341 value = lpFilter1PC(WetFilter, chans[i], value); \
342 WetPendingClicks[0] += value*WetSend * scaler; \
346 *DataPosInt += pos; \
347 *DataPosFrac = frac; \
350 DECL_TEMPLATE(ALfloat
, point32
)
351 DECL_TEMPLATE(ALfloat
, lerp32
)
352 DECL_TEMPLATE(ALfloat
, cubic32
)
354 DECL_TEMPLATE(ALshort
, point16
)
355 DECL_TEMPLATE(ALshort
, lerp16
)
356 DECL_TEMPLATE(ALshort
, cubic16
)
358 DECL_TEMPLATE(ALubyte
, point8
)
359 DECL_TEMPLATE(ALubyte
, lerp8
)
360 DECL_TEMPLATE(ALubyte
, cubic8
)
365 #define DECL_TEMPLATE(T, chans, sampler) \
366 static void Mix_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
367 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
368 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
370 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
371 const ALfloat scaler = 1.0f/Channels; \
372 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
373 ALfloat *ClickRemoval, *PendingClicks; \
375 ALfloat DrySend[OUTPUTCHANNELS]; \
382 increment = Source->Params.Step; \
384 DryBuffer = Device->DryBuffer; \
385 ClickRemoval = Device->ClickRemoval; \
386 PendingClicks = Device->PendingClicks; \
387 DryFilter = &Source->Params.iirFilter; \
388 for(i = 0;i < OUTPUTCHANNELS;i++) \
389 DrySend[i] = Source->Params.DryGains[i]; \
392 frac = *DataPosFrac; \
396 for(i = 0;i < Channels;i++) \
398 value = sampler(data + pos*Channels + i, Channels, frac); \
400 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
401 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
404 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
406 for(i = 0;i < Channels;i++) \
408 value = sampler(data + pos*Channels + i, Channels, 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, Channels, frac); \
425 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
426 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
430 for(out = 0;out < Device->NumAuxSends;out++) \
433 ALfloat *WetBuffer; \
434 ALfloat *WetClickRemoval; \
435 ALfloat *WetPendingClicks; \
438 if(!Source->Send[out].Slot || \
439 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
442 WetBuffer = Source->Send[out].Slot->WetBuffer; \
443 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
444 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
445 WetFilter = &Source->Params.Send[out].iirFilter; \
446 WetSend = Source->Params.Send[out].WetGain; \
449 frac = *DataPosFrac; \
454 for(i = 0;i < Channels;i++) \
456 value = sampler(data + pos*Channels + i, Channels, frac); \
458 value = lpFilter1PC(WetFilter, chans[i], value); \
459 WetClickRemoval[0] -= value*WetSend * scaler; \
462 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
464 for(i = 0;i < Channels;i++) \
466 value = sampler(data + pos*Channels + i, Channels, 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, Channels, frac); \
483 value = lpFilter1PC(WetFilter, chans[i], value); \
484 WetPendingClicks[0] += value*WetSend * scaler; \
488 *DataPosInt += pos; \
489 *DataPosFrac = frac; \
492 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
493 BACK_LEFT
, BACK_RIGHT
};
494 DECL_TEMPLATE(ALfloat
, QuadChans
, point32
)
495 DECL_TEMPLATE(ALfloat
, QuadChans
, lerp32
)
496 DECL_TEMPLATE(ALfloat
, QuadChans
, cubic32
)
498 DECL_TEMPLATE(ALshort
, QuadChans
, point16
)
499 DECL_TEMPLATE(ALshort
, QuadChans
, lerp16
)
500 DECL_TEMPLATE(ALshort
, QuadChans
, cubic16
)
502 DECL_TEMPLATE(ALubyte
, QuadChans
, point8
)
503 DECL_TEMPLATE(ALubyte
, QuadChans
, lerp8
)
504 DECL_TEMPLATE(ALubyte
, QuadChans
, cubic8
)
507 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
509 BACK_LEFT
, BACK_RIGHT
};
510 DECL_TEMPLATE(ALfloat
, X51Chans
, point32
)
511 DECL_TEMPLATE(ALfloat
, X51Chans
, lerp32
)
512 DECL_TEMPLATE(ALfloat
, X51Chans
, cubic32
)
514 DECL_TEMPLATE(ALshort
, X51Chans
, point16
)
515 DECL_TEMPLATE(ALshort
, X51Chans
, lerp16
)
516 DECL_TEMPLATE(ALshort
, X51Chans
, cubic16
)
518 DECL_TEMPLATE(ALubyte
, X51Chans
, point8
)
519 DECL_TEMPLATE(ALubyte
, X51Chans
, lerp8
)
520 DECL_TEMPLATE(ALubyte
, X51Chans
, cubic8
)
523 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
526 SIDE_LEFT
, SIDE_RIGHT
};
527 DECL_TEMPLATE(ALfloat
, X61Chans
, point32
)
528 DECL_TEMPLATE(ALfloat
, X61Chans
, lerp32
)
529 DECL_TEMPLATE(ALfloat
, X61Chans
, cubic32
)
531 DECL_TEMPLATE(ALshort
, X61Chans
, point16
)
532 DECL_TEMPLATE(ALshort
, X61Chans
, lerp16
)
533 DECL_TEMPLATE(ALshort
, X61Chans
, cubic16
)
535 DECL_TEMPLATE(ALubyte
, X61Chans
, point8
)
536 DECL_TEMPLATE(ALubyte
, X61Chans
, lerp8
)
537 DECL_TEMPLATE(ALubyte
, X61Chans
, cubic8
)
540 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
542 BACK_LEFT
, BACK_RIGHT
,
543 SIDE_LEFT
, SIDE_RIGHT
};
544 DECL_TEMPLATE(ALfloat
, X71Chans
, point32
)
545 DECL_TEMPLATE(ALfloat
, X71Chans
, lerp32
)
546 DECL_TEMPLATE(ALfloat
, X71Chans
, cubic32
)
548 DECL_TEMPLATE(ALshort
, X71Chans
, point16
)
549 DECL_TEMPLATE(ALshort
, X71Chans
, lerp16
)
550 DECL_TEMPLATE(ALshort
, X71Chans
, cubic16
)
552 DECL_TEMPLATE(ALubyte
, X71Chans
, point8
)
553 DECL_TEMPLATE(ALubyte
, X71Chans
, lerp8
)
554 DECL_TEMPLATE(ALubyte
, X71Chans
, cubic8
)
559 #define DECL_TEMPLATE(T, sampler) \
560 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
561 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
562 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
567 Mix_##T##_Mono_##sampler(Source, Device, \
568 Data, DataPosInt, DataPosFrac, \
569 j, SamplesToDo, BufferSize); \
571 case 2: /* Stereo */ \
572 Mix_##T##_Stereo_##sampler(Source, Device, \
573 Data, DataPosInt, DataPosFrac, \
574 j, SamplesToDo, BufferSize); \
577 Mix_##T##_QuadChans_##sampler(Source, Device, \
578 Data, DataPosInt, DataPosFrac, \
579 j, SamplesToDo, BufferSize); \
582 Mix_##T##_X51Chans_##sampler(Source, Device, \
583 Data, DataPosInt, DataPosFrac, \
584 j, SamplesToDo, BufferSize); \
587 Mix_##T##_X61Chans_##sampler(Source, Device, \
588 Data, DataPosInt, DataPosFrac, \
589 j, SamplesToDo, BufferSize); \
592 Mix_##T##_X71Chans_##sampler(Source, Device, \
593 Data, DataPosInt, DataPosFrac, \
594 j, SamplesToDo, BufferSize); \
599 DECL_TEMPLATE(ALfloat
, point32
)
600 DECL_TEMPLATE(ALfloat
, lerp32
)
601 DECL_TEMPLATE(ALfloat
, cubic32
)
603 DECL_TEMPLATE(ALshort
, point16
)
604 DECL_TEMPLATE(ALshort
, lerp16
)
605 DECL_TEMPLATE(ALshort
, cubic16
)
607 DECL_TEMPLATE(ALubyte
, point8
)
608 DECL_TEMPLATE(ALubyte
, lerp8
)
609 DECL_TEMPLATE(ALubyte
, cubic8
)
614 /* Stack data size can be whatever. Larger values need more stack, while
615 * smaller values may need more iterations */
616 #ifndef STACK_DATA_SIZE
617 #define STACK_DATA_SIZE 16384
620 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
622 ALbufferlistitem
*BufferListItem
;
623 ALuint FrameSize
, Channels
, Bytes
;
624 ALuint DataPosInt
, DataPosFrac
;
625 ALuint BuffersPlayed
;
632 /* Get source info */
633 State
= Source
->state
;
634 BuffersPlayed
= Source
->BuffersPlayed
;
635 DataPosInt
= Source
->position
;
636 DataPosFrac
= Source
->position_fraction
;
637 Looping
= Source
->bLooping
;
638 increment
= Source
->Params
.Step
;
640 /* Get buffer info */
641 FrameSize
= Channels
= Bytes
= 0;
642 BufferListItem
= Source
->queue
;
643 for(i
= 0;i
< Source
->BuffersInQueue
;i
++)
645 const ALbuffer
*ALBuffer
;
646 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
648 FrameSize
= aluFrameSizeFromFormat(ALBuffer
->format
);
649 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
650 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
653 BufferListItem
= BufferListItem
->next
;
656 /* Get current buffer queue item */
657 BufferListItem
= Source
->queue
;
658 for(i
= 0;i
< BuffersPlayed
;i
++)
659 BufferListItem
= BufferListItem
->next
;
663 ALubyte StackData
[STACK_DATA_SIZE
];
664 ALubyte
*SrcData
= StackData
;
665 ALuint SrcDataSize
= 0;
668 /* Figure out how many buffer bytes will be needed */
669 DataSize64
= SamplesToDo
-j
+1;
670 DataSize64
*= increment
;
671 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
672 DataSize64
>>= FRACTIONBITS
;
673 DataSize64
+= BUFFER_PADDING
+BUFFER_PREPADDING
;
674 DataSize64
*= FrameSize
;
676 BufferSize
= min(DataSize64
, STACK_DATA_SIZE
);
677 BufferSize
-= BufferSize
%FrameSize
;
679 if(Source
->lSourceType
== AL_STATIC
)
681 const ALbuffer
*ALBuffer
= Source
->Buffer
;
682 const ALubyte
*Data
= ALBuffer
->data
;
686 /* If current pos is beyond the loop range, do not loop */
687 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
691 if(DataPosInt
>= BUFFER_PREPADDING
)
692 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
695 DataSize
= (BUFFER_PREPADDING
-DataPosInt
)*FrameSize
;
696 DataSize
= min(BufferSize
, DataSize
);
698 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
699 SrcDataSize
+= DataSize
;
700 BufferSize
-= DataSize
;
705 /* Copy what's left to play in the source buffer, and clear the
706 * rest of the temp buffer */
707 DataSize
= ALBuffer
->size
- pos
;
708 DataSize
= min(BufferSize
, DataSize
);
710 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
711 SrcDataSize
+= DataSize
;
712 BufferSize
-= DataSize
;
714 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
715 SrcDataSize
+= BufferSize
;
716 BufferSize
-= BufferSize
;
720 ALuint LoopStart
= ALBuffer
->LoopStart
;
721 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
723 if(DataPosInt
>= LoopStart
)
725 pos
= DataPosInt
-LoopStart
;
726 while(pos
< BUFFER_PREPADDING
)
727 pos
+= LoopEnd
-LoopStart
;
728 pos
-= BUFFER_PREPADDING
;
732 else if(DataPosInt
>= BUFFER_PREPADDING
)
733 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
736 DataSize
= (BUFFER_PREPADDING
-DataPosInt
)*FrameSize
;
737 DataSize
= min(BufferSize
, DataSize
);
739 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
740 SrcDataSize
+= DataSize
;
741 BufferSize
-= DataSize
;
746 /* Copy what's left of this loop iteration, then copy repeats
747 * of the loop section */
748 DataSize
= LoopEnd
*FrameSize
- pos
;
749 DataSize
= min(BufferSize
, DataSize
);
751 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
752 SrcDataSize
+= DataSize
;
753 BufferSize
-= DataSize
;
755 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
756 while(BufferSize
> 0)
758 DataSize
= min(BufferSize
, DataSize
);
760 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
761 SrcDataSize
+= DataSize
;
762 BufferSize
-= DataSize
;
768 /* Crawl the buffer queue to fill in the temp buffer */
769 ALbufferlistitem
*BufferListIter
= BufferListItem
;
772 if(DataPosInt
>= BUFFER_PREPADDING
)
773 pos
= (DataPosInt
-BUFFER_PREPADDING
)*FrameSize
;
776 pos
= (BUFFER_PREPADDING
-DataPosInt
)*FrameSize
;
779 if(!BufferListIter
->prev
&& !Looping
)
781 ALuint DataSize
= min(BufferSize
, pos
);
783 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
784 SrcDataSize
+= DataSize
;
785 BufferSize
-= DataSize
;
793 while(BufferListIter
->next
)
794 BufferListIter
= BufferListIter
->next
;
797 BufferListIter
= BufferListIter
->prev
;
799 if(BufferListIter
->buffer
)
801 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
803 pos
= BufferListIter
->buffer
->size
- pos
;
806 pos
-= BufferListIter
->buffer
->size
;
811 while(BufferListIter
&& BufferSize
> 0)
813 const ALbuffer
*ALBuffer
;
814 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
816 const ALubyte
*Data
= ALBuffer
->data
;
817 ALuint DataSize
= ALBuffer
->size
;
819 /* Skip the data already played */
828 DataSize
= min(BufferSize
, DataSize
);
829 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
830 SrcDataSize
+= DataSize
;
831 BufferSize
-= DataSize
;
834 BufferListIter
= BufferListIter
->next
;
835 if(!BufferListIter
&& Looping
)
836 BufferListIter
= Source
->queue
;
837 else if(!BufferListIter
)
839 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
840 SrcDataSize
+= BufferSize
;
841 BufferSize
-= BufferSize
;
846 /* Figure out how many samples we can mix. */
847 DataSize64
= SrcDataSize
/ FrameSize
;
848 DataSize64
-= BUFFER_PADDING
+BUFFER_PREPADDING
;
849 DataSize64
<<= FRACTIONBITS
;
850 DataSize64
-= increment
;
852 BufferSize
= (ALuint
)((DataSize64
-DataPosFrac
+(increment
-1)) / increment
);
853 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
856 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
857 increment
, increment
/(double)(1<<FRACTIONBITS
));
859 BufferListItem
= Source
->queue
;
860 BuffersPlayed
= Source
->BuffersInQueue
;
866 SrcData
+= BUFFER_PREPADDING
*FrameSize
;
867 switch((increment
!= (1<<FRACTIONBITS
)) ? Source
->Resampler
: POINT_RESAMPLER
)
869 case POINT_RESAMPLER
:
871 Mix_ALfloat_point32(Source
, Device
, Channels
,
872 SrcData
, &DataPosInt
, &DataPosFrac
,
873 j
, SamplesToDo
, BufferSize
);
875 Mix_ALshort_point16(Source
, Device
, Channels
,
876 SrcData
, &DataPosInt
, &DataPosFrac
,
877 j
, SamplesToDo
, BufferSize
);
879 Mix_ALubyte_point8(Source
, Device
, Channels
,
880 SrcData
, &DataPosInt
, &DataPosFrac
,
881 j
, SamplesToDo
, BufferSize
);
883 case LINEAR_RESAMPLER
:
885 Mix_ALfloat_lerp32(Source
, Device
, Channels
,
886 SrcData
, &DataPosInt
, &DataPosFrac
,
887 j
, SamplesToDo
, BufferSize
);
889 Mix_ALshort_lerp16(Source
, Device
, Channels
,
890 SrcData
, &DataPosInt
, &DataPosFrac
,
891 j
, SamplesToDo
, BufferSize
);
893 Mix_ALubyte_lerp8(Source
, Device
, Channels
,
894 SrcData
, &DataPosInt
, &DataPosFrac
,
895 j
, SamplesToDo
, BufferSize
);
897 case CUBIC_RESAMPLER
:
899 Mix_ALfloat_cubic32(Source
, Device
, Channels
,
900 SrcData
, &DataPosInt
, &DataPosFrac
,
901 j
, SamplesToDo
, BufferSize
);
903 Mix_ALshort_cubic16(Source
, Device
, Channels
,
904 SrcData
, &DataPosInt
, &DataPosFrac
,
905 j
, SamplesToDo
, BufferSize
);
907 Mix_ALubyte_cubic8(Source
, Device
, Channels
,
908 SrcData
, &DataPosInt
, &DataPosFrac
,
909 j
, SamplesToDo
, BufferSize
);
917 /* Handle looping sources */
920 const ALbuffer
*ALBuffer
;
922 ALuint LoopStart
= 0;
925 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
927 DataSize
= ALBuffer
->size
/ FrameSize
;
928 if(DataSize
> DataPosInt
)
930 LoopStart
= ALBuffer
->LoopStart
;
931 LoopEnd
= ALBuffer
->LoopEnd
;
934 if(BufferListItem
->next
)
936 BufferListItem
= BufferListItem
->next
;
941 BufferListItem
= Source
->queue
;
943 if(Source
->lSourceType
== AL_STATIC
)
945 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
952 BufferListItem
= Source
->queue
;
953 BuffersPlayed
= Source
->BuffersInQueue
;
959 DataPosInt
-= DataSize
;
961 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
963 /* Update source info */
964 Source
->state
= State
;
965 Source
->BuffersPlayed
= BuffersPlayed
;
966 Source
->position
= DataPosInt
;
967 Source
->position_fraction
= DataPosFrac
;
968 Source
->Buffer
= BufferListItem
->buffer
;