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/FRACTIONONE
)); }
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/FRACTIONONE
)); }
48 static __inline ALdouble
point16(const ALshort
*vals
, ALint step
, ALint frac
)
49 { return vals
[0] * (1.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/FRACTIONONE
)) * (1.0/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/FRACTIONONE
)) * (1.0/32767.0); }
56 static __inline ALdouble
point8(const ALubyte
*vals
, ALint step
, ALint frac
)
57 { return (vals
[0]-128.0) * (1.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
],
60 frac
* (1.0/FRACTIONONE
))-128.0) * (1.0/127.0); }
61 static __inline ALdouble
cubic8(const ALubyte
*vals
, ALint step
, ALint frac
)
62 { return (cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
63 frac
* (1.0/FRACTIONONE
))-128.0) * (1.0/127.0); }
66 #define DECL_TEMPLATE(T, sampler) \
67 static void Mix_##T##_Mono_##sampler(ALsource *Source, ALCdevice *Device, \
68 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
69 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
71 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
72 ALfloat *ClickRemoval, *PendingClicks; \
74 ALfloat DrySend[OUTPUTCHANNELS]; \
81 increment = Source->Params.Step; \
83 DryBuffer = Device->DryBuffer; \
84 ClickRemoval = Device->ClickRemoval; \
85 PendingClicks = Device->PendingClicks; \
86 DryFilter = &Source->Params.iirFilter; \
87 for(i = 0;i < OUTPUTCHANNELS;i++) \
88 DrySend[i] = Source->Params.DryGains[i]; \
91 frac = *DataPosFrac; \
95 value = sampler(data+pos, 1, frac); \
97 value = lpFilter4PC(DryFilter, 0, value); \
98 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
99 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
100 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
101 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
102 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
103 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
104 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
105 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
107 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
109 /* First order interpolator */ \
110 value = sampler(data+pos, 1, frac); \
112 /* Direct path final mix buffer and panning */ \
113 value = lpFilter4P(DryFilter, 0, value); \
114 DryBuffer[OutPos][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
115 DryBuffer[OutPos][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
116 DryBuffer[OutPos][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
117 DryBuffer[OutPos][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
118 DryBuffer[OutPos][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
119 DryBuffer[OutPos][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
120 DryBuffer[OutPos][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
121 DryBuffer[OutPos][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
124 pos += frac>>FRACTIONBITS; \
125 frac &= FRACTIONMASK; \
128 if(OutPos == SamplesToDo) \
130 value = sampler(data+pos, 1, frac); \
132 value = lpFilter4PC(DryFilter, 0, value); \
133 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
134 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
135 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
136 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
137 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
138 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
139 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
140 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
143 for(out = 0;out < Device->NumAuxSends;out++) \
146 ALfloat *WetBuffer; \
147 ALfloat *WetClickRemoval; \
148 ALfloat *WetPendingClicks; \
151 if(!Source->Send[out].Slot || \
152 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
155 WetBuffer = Source->Send[out].Slot->WetBuffer; \
156 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
157 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
158 WetFilter = &Source->Params.Send[out].iirFilter; \
159 WetSend = Source->Params.Send[out].WetGain; \
162 frac = *DataPosFrac; \
163 OutPos -= BufferSize; \
167 value = sampler(data+pos, 1, frac); \
169 value = lpFilter2PC(WetFilter, 0, value); \
170 WetClickRemoval[0] -= value*WetSend; \
172 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
174 /* First order interpolator */ \
175 value = sampler(data+pos, 1, frac); \
177 /* Room path final mix buffer and panning */ \
178 value = lpFilter2P(WetFilter, 0, value); \
179 WetBuffer[OutPos] += value*WetSend; \
182 pos += frac>>FRACTIONBITS; \
183 frac &= FRACTIONMASK; \
186 if(OutPos == SamplesToDo) \
188 value = sampler(data+pos, 1, frac); \
190 value = lpFilter2PC(WetFilter, 0, value); \
191 WetPendingClicks[0] += value*WetSend; \
194 *DataPosInt += pos; \
195 *DataPosFrac = frac; \
198 DECL_TEMPLATE(ALfloat
, point32
)
199 DECL_TEMPLATE(ALfloat
, lerp32
)
200 DECL_TEMPLATE(ALfloat
, cubic32
)
202 DECL_TEMPLATE(ALshort
, point16
)
203 DECL_TEMPLATE(ALshort
, lerp16
)
204 DECL_TEMPLATE(ALshort
, cubic16
)
206 DECL_TEMPLATE(ALubyte
, point8
)
207 DECL_TEMPLATE(ALubyte
, lerp8
)
208 DECL_TEMPLATE(ALubyte
, cubic8
)
213 #define DECL_TEMPLATE(T, sampler) \
214 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
215 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
216 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
218 static const ALuint Channels = 2; \
219 static const Channel chans[] = { \
220 FRONT_LEFT, FRONT_RIGHT, \
221 SIDE_LEFT, SIDE_RIGHT, \
222 BACK_LEFT, BACK_RIGHT \
224 const ALfloat scaler = 1.0f/Channels; \
225 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
226 ALfloat *ClickRemoval, *PendingClicks; \
228 ALfloat DrySend[OUTPUTCHANNELS]; \
235 increment = Source->Params.Step; \
237 DryBuffer = Device->DryBuffer; \
238 ClickRemoval = Device->ClickRemoval; \
239 PendingClicks = Device->PendingClicks; \
240 DryFilter = &Source->Params.iirFilter; \
241 for(i = 0;i < OUTPUTCHANNELS;i++) \
242 DrySend[i] = Source->Params.DryGains[i]; \
245 frac = *DataPosFrac; \
249 for(i = 0;i < Channels;i++) \
251 value = sampler(data + pos*Channels + i, Channels, frac); \
253 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
254 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
255 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
256 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
259 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
261 for(i = 0;i < Channels;i++) \
263 value = sampler(data + pos*Channels + i, Channels, frac); \
265 value = lpFilter2P(DryFilter, chans[i]*2, value); \
266 DryBuffer[OutPos][chans[i+0]] += value*DrySend[chans[i+0]]; \
267 DryBuffer[OutPos][chans[i+2]] += value*DrySend[chans[i+2]]; \
268 DryBuffer[OutPos][chans[i+4]] += value*DrySend[chans[i+4]]; \
272 pos += frac>>FRACTIONBITS; \
273 frac &= FRACTIONMASK; \
276 if(OutPos == SamplesToDo) \
278 for(i = 0;i < Channels;i++) \
280 value = sampler(data + pos*Channels + i, Channels, frac); \
282 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
283 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
284 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
285 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
289 for(out = 0;out < Device->NumAuxSends;out++) \
292 ALfloat *WetBuffer; \
293 ALfloat *WetClickRemoval; \
294 ALfloat *WetPendingClicks; \
297 if(!Source->Send[out].Slot || \
298 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
301 WetBuffer = Source->Send[out].Slot->WetBuffer; \
302 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
303 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
304 WetFilter = &Source->Params.Send[out].iirFilter; \
305 WetSend = Source->Params.Send[out].WetGain; \
308 frac = *DataPosFrac; \
309 OutPos -= BufferSize; \
313 for(i = 0;i < Channels;i++) \
315 value = sampler(data + pos*Channels + i, Channels, frac); \
317 value = lpFilter1PC(WetFilter, chans[i], value); \
318 WetClickRemoval[0] -= value*WetSend * scaler; \
321 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
323 for(i = 0;i < Channels;i++) \
325 value = sampler(data + pos*Channels + i, Channels, frac); \
327 value = lpFilter1P(WetFilter, chans[i], value); \
328 WetBuffer[OutPos] += value*WetSend * scaler; \
332 pos += frac>>FRACTIONBITS; \
333 frac &= FRACTIONMASK; \
336 if(OutPos == SamplesToDo) \
338 for(i = 0;i < Channels;i++) \
340 value = sampler(data + pos*Channels + i, Channels, frac); \
342 value = lpFilter1PC(WetFilter, chans[i], value); \
343 WetPendingClicks[0] += value*WetSend * scaler; \
347 *DataPosInt += pos; \
348 *DataPosFrac = frac; \
351 DECL_TEMPLATE(ALfloat
, point32
)
352 DECL_TEMPLATE(ALfloat
, lerp32
)
353 DECL_TEMPLATE(ALfloat
, cubic32
)
355 DECL_TEMPLATE(ALshort
, point16
)
356 DECL_TEMPLATE(ALshort
, lerp16
)
357 DECL_TEMPLATE(ALshort
, cubic16
)
359 DECL_TEMPLATE(ALubyte
, point8
)
360 DECL_TEMPLATE(ALubyte
, lerp8
)
361 DECL_TEMPLATE(ALubyte
, cubic8
)
366 #define DECL_TEMPLATE(T, chans, sampler) \
367 static void Mix_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
368 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
369 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
371 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
372 const ALfloat scaler = 1.0f/Channels; \
373 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
374 ALfloat *ClickRemoval, *PendingClicks; \
376 ALfloat DrySend[OUTPUTCHANNELS]; \
383 increment = Source->Params.Step; \
385 DryBuffer = Device->DryBuffer; \
386 ClickRemoval = Device->ClickRemoval; \
387 PendingClicks = Device->PendingClicks; \
388 DryFilter = &Source->Params.iirFilter; \
389 for(i = 0;i < OUTPUTCHANNELS;i++) \
390 DrySend[i] = Source->Params.DryGains[i]; \
393 frac = *DataPosFrac; \
397 for(i = 0;i < Channels;i++) \
399 value = sampler(data + pos*Channels + i, Channels, frac); \
401 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
402 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
405 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
407 for(i = 0;i < Channels;i++) \
409 value = sampler(data + pos*Channels + i, Channels, frac); \
411 value = lpFilter2P(DryFilter, chans[i]*2, value); \
412 DryBuffer[OutPos][chans[i]] += value*DrySend[chans[i]]; \
416 pos += frac>>FRACTIONBITS; \
417 frac &= FRACTIONMASK; \
420 if(OutPos == SamplesToDo) \
422 for(i = 0;i < Channels;i++) \
424 value = sampler(data + pos*Channels + i, Channels, 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; \
451 OutPos -= BufferSize; \
455 for(i = 0;i < Channels;i++) \
457 value = sampler(data + pos*Channels + i, Channels, frac); \
459 value = lpFilter1PC(WetFilter, chans[i], value); \
460 WetClickRemoval[0] -= value*WetSend * scaler; \
463 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
465 for(i = 0;i < Channels;i++) \
467 value = sampler(data + pos*Channels + i, Channels, frac); \
469 value = lpFilter1P(WetFilter, chans[i], value); \
470 WetBuffer[OutPos] += value*WetSend * scaler; \
474 pos += frac>>FRACTIONBITS; \
475 frac &= FRACTIONMASK; \
478 if(OutPos == SamplesToDo) \
480 for(i = 0;i < Channels;i++) \
482 value = sampler(data + pos*Channels + i, Channels, 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_TEMPLATE(ALfloat
, QuadChans
, point32
)
496 DECL_TEMPLATE(ALfloat
, QuadChans
, lerp32
)
497 DECL_TEMPLATE(ALfloat
, QuadChans
, cubic32
)
499 DECL_TEMPLATE(ALshort
, QuadChans
, point16
)
500 DECL_TEMPLATE(ALshort
, QuadChans
, lerp16
)
501 DECL_TEMPLATE(ALshort
, QuadChans
, cubic16
)
503 DECL_TEMPLATE(ALubyte
, QuadChans
, point8
)
504 DECL_TEMPLATE(ALubyte
, QuadChans
, lerp8
)
505 DECL_TEMPLATE(ALubyte
, QuadChans
, cubic8
)
508 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
510 BACK_LEFT
, BACK_RIGHT
};
511 DECL_TEMPLATE(ALfloat
, X51Chans
, point32
)
512 DECL_TEMPLATE(ALfloat
, X51Chans
, lerp32
)
513 DECL_TEMPLATE(ALfloat
, X51Chans
, cubic32
)
515 DECL_TEMPLATE(ALshort
, X51Chans
, point16
)
516 DECL_TEMPLATE(ALshort
, X51Chans
, lerp16
)
517 DECL_TEMPLATE(ALshort
, X51Chans
, cubic16
)
519 DECL_TEMPLATE(ALubyte
, X51Chans
, point8
)
520 DECL_TEMPLATE(ALubyte
, X51Chans
, lerp8
)
521 DECL_TEMPLATE(ALubyte
, X51Chans
, cubic8
)
524 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
527 SIDE_LEFT
, SIDE_RIGHT
};
528 DECL_TEMPLATE(ALfloat
, X61Chans
, point32
)
529 DECL_TEMPLATE(ALfloat
, X61Chans
, lerp32
)
530 DECL_TEMPLATE(ALfloat
, X61Chans
, cubic32
)
532 DECL_TEMPLATE(ALshort
, X61Chans
, point16
)
533 DECL_TEMPLATE(ALshort
, X61Chans
, lerp16
)
534 DECL_TEMPLATE(ALshort
, X61Chans
, cubic16
)
536 DECL_TEMPLATE(ALubyte
, X61Chans
, point8
)
537 DECL_TEMPLATE(ALubyte
, X61Chans
, lerp8
)
538 DECL_TEMPLATE(ALubyte
, X61Chans
, cubic8
)
541 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
543 BACK_LEFT
, BACK_RIGHT
,
544 SIDE_LEFT
, SIDE_RIGHT
};
545 DECL_TEMPLATE(ALfloat
, X71Chans
, point32
)
546 DECL_TEMPLATE(ALfloat
, X71Chans
, lerp32
)
547 DECL_TEMPLATE(ALfloat
, X71Chans
, cubic32
)
549 DECL_TEMPLATE(ALshort
, X71Chans
, point16
)
550 DECL_TEMPLATE(ALshort
, X71Chans
, lerp16
)
551 DECL_TEMPLATE(ALshort
, X71Chans
, cubic16
)
553 DECL_TEMPLATE(ALubyte
, X71Chans
, point8
)
554 DECL_TEMPLATE(ALubyte
, X71Chans
, lerp8
)
555 DECL_TEMPLATE(ALubyte
, X71Chans
, cubic8
)
560 #define DECL_TEMPLATE(T, sampler) \
561 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
562 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
563 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
568 Mix_##T##_Mono_##sampler(Source, Device, \
569 Data, DataPosInt, DataPosFrac, \
570 OutPos, SamplesToDo, BufferSize); \
572 case 2: /* Stereo */ \
573 Mix_##T##_Stereo_##sampler(Source, Device, \
574 Data, DataPosInt, DataPosFrac, \
575 OutPos, SamplesToDo, BufferSize); \
578 Mix_##T##_QuadChans_##sampler(Source, Device, \
579 Data, DataPosInt, DataPosFrac, \
580 OutPos, SamplesToDo, BufferSize); \
583 Mix_##T##_X51Chans_##sampler(Source, Device, \
584 Data, DataPosInt, DataPosFrac, \
585 OutPos, SamplesToDo, BufferSize); \
588 Mix_##T##_X61Chans_##sampler(Source, Device, \
589 Data, DataPosInt, DataPosFrac, \
590 OutPos, SamplesToDo, BufferSize); \
593 Mix_##T##_X71Chans_##sampler(Source, Device, \
594 Data, DataPosInt, DataPosFrac, \
595 OutPos, SamplesToDo, BufferSize); \
600 DECL_TEMPLATE(ALfloat
, point32
)
601 DECL_TEMPLATE(ALfloat
, lerp32
)
602 DECL_TEMPLATE(ALfloat
, cubic32
)
604 DECL_TEMPLATE(ALshort
, point16
)
605 DECL_TEMPLATE(ALshort
, lerp16
)
606 DECL_TEMPLATE(ALshort
, cubic16
)
608 DECL_TEMPLATE(ALubyte
, point8
)
609 DECL_TEMPLATE(ALubyte
, lerp8
)
610 DECL_TEMPLATE(ALubyte
, cubic8
)
615 /* Stack data size can be whatever. Larger values need more stack, while
616 * smaller values may need more iterations */
617 #ifndef STACK_DATA_SIZE
618 #define STACK_DATA_SIZE 16384
621 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
623 ALbufferlistitem
*BufferListItem
;
624 ALuint FrameSize
, Channels
, Bytes
;
625 ALuint DataPosInt
, DataPosFrac
;
626 ALuint BuffersPlayed
;
629 resampler_t Resampler
;
635 /* Get source info */
636 State
= Source
->state
;
637 BuffersPlayed
= Source
->BuffersPlayed
;
638 DataPosInt
= Source
->position
;
639 DataPosFrac
= Source
->position_fraction
;
640 Looping
= Source
->bLooping
;
641 increment
= Source
->Params
.Step
;
642 Resampler
= (increment
== FRACTIONONE
) ? POINT_RESAMPLER
:
645 /* Get buffer info */
646 FrameSize
= Channels
= Bytes
= 0;
647 BufferListItem
= Source
->queue
;
648 for(i
= 0;i
< Source
->BuffersInQueue
;i
++)
650 const ALbuffer
*ALBuffer
;
651 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
653 FrameSize
= aluFrameSizeFromFormat(ALBuffer
->format
);
654 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
655 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
658 BufferListItem
= BufferListItem
->next
;
661 /* Get current buffer queue item */
662 BufferListItem
= Source
->queue
;
663 for(i
= 0;i
< BuffersPlayed
;i
++)
664 BufferListItem
= BufferListItem
->next
;
668 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
669 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
670 ALubyte StackData
[STACK_DATA_SIZE
];
671 ALubyte
*SrcData
= StackData
;
672 ALuint SrcDataSize
= 0;
675 /* Figure out how many buffer bytes will be needed */
676 DataSize64
= SamplesToDo
-OutPos
+1;
677 DataSize64
*= increment
;
678 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
679 DataSize64
>>= FRACTIONBITS
;
680 DataSize64
+= BufferPadding
+BufferPrePadding
;
681 DataSize64
*= FrameSize
;
683 BufferSize
= min(DataSize64
, STACK_DATA_SIZE
);
684 BufferSize
-= BufferSize
%FrameSize
;
686 if(Source
->lSourceType
== AL_STATIC
)
688 const ALbuffer
*ALBuffer
= Source
->Buffer
;
689 const ALubyte
*Data
= ALBuffer
->data
;
693 /* If current pos is beyond the loop range, do not loop */
694 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
698 if(DataPosInt
>= BufferPrePadding
)
699 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
702 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
703 DataSize
= min(BufferSize
, DataSize
);
705 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
706 SrcDataSize
+= DataSize
;
707 BufferSize
-= DataSize
;
712 /* Copy what's left to play in the source buffer, and clear the
713 * rest of the temp buffer */
714 DataSize
= ALBuffer
->size
- pos
;
715 DataSize
= min(BufferSize
, DataSize
);
717 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
718 SrcDataSize
+= DataSize
;
719 BufferSize
-= DataSize
;
721 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
722 SrcDataSize
+= BufferSize
;
723 BufferSize
-= BufferSize
;
727 ALuint LoopStart
= ALBuffer
->LoopStart
;
728 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
730 if(DataPosInt
>= LoopStart
)
732 pos
= DataPosInt
-LoopStart
;
733 while(pos
< BufferPrePadding
)
734 pos
+= LoopEnd
-LoopStart
;
735 pos
-= BufferPrePadding
;
739 else if(DataPosInt
>= BufferPrePadding
)
740 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
743 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
744 DataSize
= min(BufferSize
, DataSize
);
746 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
747 SrcDataSize
+= DataSize
;
748 BufferSize
-= DataSize
;
753 /* Copy what's left of this loop iteration, then copy repeats
754 * of the loop section */
755 DataSize
= LoopEnd
*FrameSize
- pos
;
756 DataSize
= min(BufferSize
, DataSize
);
758 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
759 SrcDataSize
+= DataSize
;
760 BufferSize
-= DataSize
;
762 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
763 while(BufferSize
> 0)
765 DataSize
= min(BufferSize
, DataSize
);
767 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
768 SrcDataSize
+= DataSize
;
769 BufferSize
-= DataSize
;
775 /* Crawl the buffer queue to fill in the temp buffer */
776 ALbufferlistitem
*BufferListIter
= BufferListItem
;
779 if(DataPosInt
>= BufferPrePadding
)
780 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
783 pos
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
786 if(!BufferListIter
->prev
&& !Looping
)
788 ALuint DataSize
= min(BufferSize
, pos
);
790 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, DataSize
);
791 SrcDataSize
+= DataSize
;
792 BufferSize
-= DataSize
;
800 while(BufferListIter
->next
)
801 BufferListIter
= BufferListIter
->next
;
804 BufferListIter
= BufferListIter
->prev
;
806 if(BufferListIter
->buffer
)
808 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
810 pos
= BufferListIter
->buffer
->size
- pos
;
813 pos
-= BufferListIter
->buffer
->size
;
818 while(BufferListIter
&& BufferSize
> 0)
820 const ALbuffer
*ALBuffer
;
821 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
823 const ALubyte
*Data
= ALBuffer
->data
;
824 ALuint DataSize
= ALBuffer
->size
;
826 /* Skip the data already played */
835 DataSize
= min(BufferSize
, DataSize
);
836 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
837 SrcDataSize
+= DataSize
;
838 BufferSize
-= DataSize
;
841 BufferListIter
= BufferListIter
->next
;
842 if(!BufferListIter
&& Looping
)
843 BufferListIter
= Source
->queue
;
844 else if(!BufferListIter
)
846 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
847 SrcDataSize
+= BufferSize
;
848 BufferSize
-= BufferSize
;
853 /* Figure out how many samples we can mix. */
854 DataSize64
= SrcDataSize
/ FrameSize
;
855 DataSize64
-= BufferPadding
+BufferPrePadding
;
856 DataSize64
<<= FRACTIONBITS
;
857 DataSize64
-= increment
;
859 BufferSize
= (ALuint
)((DataSize64
-DataPosFrac
+(increment
-1)) / increment
);
860 BufferSize
= min(BufferSize
, (SamplesToDo
-OutPos
));
863 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
864 increment
, increment
/(double)FRACTIONONE
);
866 BufferListItem
= Source
->queue
;
867 BuffersPlayed
= Source
->BuffersInQueue
;
873 SrcData
+= BufferPrePadding
*FrameSize
;
876 case POINT_RESAMPLER
:
878 Mix_ALfloat_point32(Source
, Device
, Channels
,
879 SrcData
, &DataPosInt
, &DataPosFrac
,
880 OutPos
, SamplesToDo
, BufferSize
);
882 Mix_ALshort_point16(Source
, Device
, Channels
,
883 SrcData
, &DataPosInt
, &DataPosFrac
,
884 OutPos
, SamplesToDo
, BufferSize
);
886 Mix_ALubyte_point8(Source
, Device
, Channels
,
887 SrcData
, &DataPosInt
, &DataPosFrac
,
888 OutPos
, SamplesToDo
, BufferSize
);
890 case LINEAR_RESAMPLER
:
892 Mix_ALfloat_lerp32(Source
, Device
, Channels
,
893 SrcData
, &DataPosInt
, &DataPosFrac
,
894 OutPos
, SamplesToDo
, BufferSize
);
896 Mix_ALshort_lerp16(Source
, Device
, Channels
,
897 SrcData
, &DataPosInt
, &DataPosFrac
,
898 OutPos
, SamplesToDo
, BufferSize
);
900 Mix_ALubyte_lerp8(Source
, Device
, Channels
,
901 SrcData
, &DataPosInt
, &DataPosFrac
,
902 OutPos
, SamplesToDo
, BufferSize
);
904 case CUBIC_RESAMPLER
:
906 Mix_ALfloat_cubic32(Source
, Device
, Channels
,
907 SrcData
, &DataPosInt
, &DataPosFrac
,
908 OutPos
, SamplesToDo
, BufferSize
);
910 Mix_ALshort_cubic16(Source
, Device
, Channels
,
911 SrcData
, &DataPosInt
, &DataPosFrac
,
912 OutPos
, SamplesToDo
, BufferSize
);
914 Mix_ALubyte_cubic8(Source
, Device
, Channels
,
915 SrcData
, &DataPosInt
, &DataPosFrac
,
916 OutPos
, SamplesToDo
, BufferSize
);
922 OutPos
+= BufferSize
;
924 /* Handle looping sources */
927 const ALbuffer
*ALBuffer
;
929 ALuint LoopStart
= 0;
932 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
934 DataSize
= ALBuffer
->size
/ FrameSize
;
935 if(DataSize
> DataPosInt
)
937 LoopStart
= ALBuffer
->LoopStart
;
938 LoopEnd
= ALBuffer
->LoopEnd
;
941 if(BufferListItem
->next
)
943 BufferListItem
= BufferListItem
->next
;
948 BufferListItem
= Source
->queue
;
950 if(Source
->lSourceType
== AL_STATIC
)
952 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
959 BufferListItem
= Source
->queue
;
960 BuffersPlayed
= Source
->BuffersInQueue
;
966 DataPosInt
-= DataSize
;
968 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
970 /* Update source info */
971 Source
->state
= State
;
972 Source
->BuffersPlayed
= BuffersPlayed
;
973 Source
->position
= DataPosInt
;
974 Source
->position_fraction
= DataPosFrac
;
975 Source
->Buffer
= BufferListItem
->buffer
;