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 ALfloat
point32(ALfloat val1
, ALfloat val2
, ALint frac
)
46 static __inline ALfloat
lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
48 val1
+= ((val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
))));
51 static __inline ALfloat
cos_lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
53 val1
+= ((val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5));
57 static __inline ALfloat
point16(ALfloat val1
, ALfloat val2
, ALint frac
)
59 return val1
/ 32767.0f
;
63 static __inline ALfloat
lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
65 val1
+= (val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
)));
66 return val1
/ 32767.0f
;
68 static __inline ALfloat
cos_lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
70 val1
+= (val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5);
71 return val1
/ 32767.0f
;
74 static __inline ALfloat
point8(ALfloat val1
, ALfloat val2
, ALint frac
)
76 return (val1
-128.0f
) / 127.0f
;
80 static __inline ALfloat
lerp8(ALfloat val1
, ALfloat val2
, ALint frac
)
82 val1
+= (val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
)));
83 return (val1
-128.0f
) / 127.0f
;
85 static __inline ALfloat
cos_lerp8(ALfloat val1
, ALfloat val2
, ALint frac
)
87 val1
+= (val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5);
88 return (val1
-128.0f
) / 127.0f
;
92 #define DECL_MIX_MONO(T,sampler) \
93 static void MixMono_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
94 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
95 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
97 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
98 ALfloat *ClickRemoval, *PendingClicks; \
100 ALfloat DrySend[OUTPUTCHANNELS]; \
107 increment = Source->Params.Step; \
109 DryBuffer = Device->DryBuffer; \
110 ClickRemoval = Device->ClickRemoval; \
111 PendingClicks = Device->PendingClicks; \
112 DryFilter = &Source->Params.iirFilter; \
113 for(i = 0;i < OUTPUTCHANNELS;i++) \
114 DrySend[i] = Source->Params.DryGains[i]; \
117 frac = *DataPosFrac; \
121 value = sampler(data[pos], data[pos+1], frac); \
123 value = lpFilter4PC(DryFilter, 0, value); \
124 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
125 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
126 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
127 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
128 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
129 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
130 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
131 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
133 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
135 /* First order interpolator */ \
136 value = sampler(data[pos], data[pos+1], frac); \
138 /* Direct path final mix buffer and panning */ \
139 value = lpFilter4P(DryFilter, 0, value); \
140 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
141 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
142 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
143 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
144 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
145 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
146 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
147 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
150 pos += frac>>FRACTIONBITS; \
151 frac &= FRACTIONMASK; \
154 if(j == SamplesToDo) \
156 value = sampler(data[pos], data[pos+1], frac); \
158 value = lpFilter4PC(DryFilter, 0, value); \
159 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
160 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
161 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
162 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
163 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
164 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
165 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
166 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
169 for(out = 0;out < Device->NumAuxSends;out++) \
172 ALfloat *WetBuffer; \
173 ALfloat *WetClickRemoval; \
174 ALfloat *WetPendingClicks; \
177 if(!Source->Send[out].Slot || \
178 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
181 WetBuffer = Source->Send[out].Slot->WetBuffer; \
182 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
183 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
184 WetFilter = &Source->Params.Send[out].iirFilter; \
185 WetSend = Source->Params.Send[out].WetGain; \
188 frac = *DataPosFrac; \
193 value = sampler(data[pos], data[pos+1], frac); \
195 value = lpFilter2PC(WetFilter, 0, value); \
196 WetClickRemoval[0] -= value*WetSend; \
198 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
200 /* First order interpolator */ \
201 value = sampler(data[pos], data[pos+1], frac); \
203 /* Room path final mix buffer and panning */ \
204 value = lpFilter2P(WetFilter, 0, value); \
205 WetBuffer[j] += value*WetSend; \
208 pos += frac>>FRACTIONBITS; \
209 frac &= FRACTIONMASK; \
212 if(j == SamplesToDo) \
214 value = sampler(data[pos], data[pos+1], frac); \
216 value = lpFilter2PC(WetFilter, 0, value); \
217 WetPendingClicks[0] += value*WetSend; \
220 *DataPosInt += pos; \
221 *DataPosFrac = frac; \
224 DECL_MIX_MONO(ALfloat
, point32
)
225 DECL_MIX_MONO(ALfloat
, lerp32
)
226 DECL_MIX_MONO(ALfloat
, cos_lerp32
)
228 DECL_MIX_MONO(ALshort
, point16
)
229 DECL_MIX_MONO(ALshort
, lerp16
)
230 DECL_MIX_MONO(ALshort
, cos_lerp16
)
232 DECL_MIX_MONO(ALubyte
, point8
)
233 DECL_MIX_MONO(ALubyte
, lerp8
)
234 DECL_MIX_MONO(ALubyte
, cos_lerp8
)
237 #define DECL_MIX_STEREO(T,sampler) \
238 static void MixStereo_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
239 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
240 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
242 static const ALuint Channels = 2; \
243 static const Channel chans[] = { \
244 FRONT_LEFT, FRONT_RIGHT, \
245 SIDE_LEFT, SIDE_RIGHT, \
246 BACK_LEFT, BACK_RIGHT \
248 const ALfloat scaler = 1.0f/Channels; \
249 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
250 ALfloat *ClickRemoval, *PendingClicks; \
252 ALfloat DrySend[OUTPUTCHANNELS]; \
259 increment = Source->Params.Step; \
261 DryBuffer = Device->DryBuffer; \
262 ClickRemoval = Device->ClickRemoval; \
263 PendingClicks = Device->PendingClicks; \
264 DryFilter = &Source->Params.iirFilter; \
265 for(i = 0;i < OUTPUTCHANNELS;i++) \
266 DrySend[i] = Source->Params.DryGains[i]; \
269 frac = *DataPosFrac; \
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 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
280 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
281 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
284 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
286 for(i = 0;i < Channels;i++) \
288 value = sampler(data[pos*Channels + i], \
289 data[(pos+1)*Channels + i], frac); \
291 value = lpFilter2P(DryFilter, chans[i]*2, value); \
292 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
293 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
294 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
298 pos += frac>>FRACTIONBITS; \
299 frac &= FRACTIONMASK; \
302 if(j == SamplesToDo) \
304 for(i = 0;i < Channels;i++) \
306 value = sampler(data[pos*Channels + i], \
307 data[(pos+1)*Channels + i], frac); \
309 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
310 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
311 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
312 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
316 for(out = 0;out < Device->NumAuxSends;out++) \
319 ALfloat *WetBuffer; \
320 ALfloat *WetClickRemoval; \
321 ALfloat *WetPendingClicks; \
324 if(!Source->Send[out].Slot || \
325 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
328 WetBuffer = Source->Send[out].Slot->WetBuffer; \
329 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
330 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
331 WetFilter = &Source->Params.Send[out].iirFilter; \
332 WetSend = Source->Params.Send[out].WetGain; \
335 frac = *DataPosFrac; \
340 for(i = 0;i < Channels;i++) \
342 value = sampler(data[pos*Channels + i], \
343 data[(pos+1)*Channels + i], frac); \
345 value = lpFilter1PC(WetFilter, chans[i], value); \
346 WetClickRemoval[0] -= value*WetSend * scaler; \
349 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
351 for(i = 0;i < Channels;i++) \
353 value = sampler(data[pos*Channels + i], \
354 data[(pos+1)*Channels + i], frac); \
356 value = lpFilter1P(WetFilter, chans[i], value); \
357 WetBuffer[j] += value*WetSend * scaler; \
361 pos += frac>>FRACTIONBITS; \
362 frac &= FRACTIONMASK; \
365 if(j == SamplesToDo) \
367 for(i = 0;i < Channels;i++) \
369 value = sampler(data[pos*Channels + i], \
370 data[(pos+1)*Channels + i], frac); \
372 value = lpFilter1PC(WetFilter, chans[i], value); \
373 WetPendingClicks[0] += value*WetSend * scaler; \
377 *DataPosInt += pos; \
378 *DataPosFrac = frac; \
381 DECL_MIX_STEREO(ALfloat
, point32
)
382 DECL_MIX_STEREO(ALfloat
, lerp32
)
383 DECL_MIX_STEREO(ALfloat
, cos_lerp32
)
385 DECL_MIX_STEREO(ALshort
, point16
)
386 DECL_MIX_STEREO(ALshort
, lerp16
)
387 DECL_MIX_STEREO(ALshort
, cos_lerp16
)
389 DECL_MIX_STEREO(ALubyte
, point8
)
390 DECL_MIX_STEREO(ALubyte
, lerp8
)
391 DECL_MIX_STEREO(ALubyte
, cos_lerp8
)
394 #define DECL_MIX_MC(T,chans,sampler) \
395 static void MixMC_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
396 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
397 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
399 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
400 const ALfloat scaler = 1.0f/Channels; \
401 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
402 ALfloat *ClickRemoval, *PendingClicks; \
404 ALfloat DrySend[OUTPUTCHANNELS]; \
411 increment = Source->Params.Step; \
413 DryBuffer = Device->DryBuffer; \
414 ClickRemoval = Device->ClickRemoval; \
415 PendingClicks = Device->PendingClicks; \
416 DryFilter = &Source->Params.iirFilter; \
417 for(i = 0;i < OUTPUTCHANNELS;i++) \
418 DrySend[i] = Source->Params.DryGains[i]; \
421 frac = *DataPosFrac; \
425 for(i = 0;i < Channels;i++) \
427 value = sampler(data[pos*Channels + i], \
428 data[(pos+1)*Channels + i], frac); \
430 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
431 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
434 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
436 for(i = 0;i < Channels;i++) \
438 value = sampler(data[pos*Channels + i], \
439 data[(pos+1)*Channels + i], frac); \
441 value = lpFilter2P(DryFilter, chans[i]*2, value); \
442 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
446 pos += frac>>FRACTIONBITS; \
447 frac &= FRACTIONMASK; \
450 if(j == SamplesToDo) \
452 for(i = 0;i < Channels;i++) \
454 value = sampler(data[pos*Channels + i], \
455 data[(pos+1)*Channels + i], frac); \
457 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
458 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
462 for(out = 0;out < Device->NumAuxSends;out++) \
465 ALfloat *WetBuffer; \
466 ALfloat *WetClickRemoval; \
467 ALfloat *WetPendingClicks; \
470 if(!Source->Send[out].Slot || \
471 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
474 WetBuffer = Source->Send[out].Slot->WetBuffer; \
475 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
476 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
477 WetFilter = &Source->Params.Send[out].iirFilter; \
478 WetSend = Source->Params.Send[out].WetGain; \
481 frac = *DataPosFrac; \
486 for(i = 0;i < Channels;i++) \
488 value = sampler(data[pos*Channels + i], \
489 data[(pos+1)*Channels + i], frac); \
491 value = lpFilter1PC(WetFilter, chans[i], value); \
492 WetClickRemoval[0] -= value*WetSend * scaler; \
495 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
497 for(i = 0;i < Channels;i++) \
499 value = sampler(data[pos*Channels + i], \
500 data[(pos+1)*Channels + i], frac); \
502 value = lpFilter1P(WetFilter, chans[i], value); \
503 WetBuffer[j] += value*WetSend * scaler; \
507 pos += frac>>FRACTIONBITS; \
508 frac &= FRACTIONMASK; \
511 if(j == SamplesToDo) \
513 for(i = 0;i < Channels;i++) \
515 value = sampler(data[pos*Channels + i], \
516 data[(pos+1)*Channels + i], frac); \
518 value = lpFilter1PC(WetFilter, chans[i], value); \
519 WetPendingClicks[0] += value*WetSend * scaler; \
523 *DataPosInt += pos; \
524 *DataPosFrac = frac; \
527 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
528 BACK_LEFT
, BACK_RIGHT
};
529 DECL_MIX_MC(ALfloat
, QuadChans
, point32
)
530 DECL_MIX_MC(ALfloat
, QuadChans
, lerp32
)
531 DECL_MIX_MC(ALfloat
, QuadChans
, cos_lerp32
)
533 DECL_MIX_MC(ALshort
, QuadChans
, point16
)
534 DECL_MIX_MC(ALshort
, QuadChans
, lerp16
)
535 DECL_MIX_MC(ALshort
, QuadChans
, cos_lerp16
)
537 DECL_MIX_MC(ALubyte
, QuadChans
, point8
)
538 DECL_MIX_MC(ALubyte
, QuadChans
, lerp8
)
539 DECL_MIX_MC(ALubyte
, QuadChans
, cos_lerp8
)
542 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
544 BACK_LEFT
, BACK_RIGHT
};
545 DECL_MIX_MC(ALfloat
, X51Chans
, point32
)
546 DECL_MIX_MC(ALfloat
, X51Chans
, lerp32
)
547 DECL_MIX_MC(ALfloat
, X51Chans
, cos_lerp32
)
549 DECL_MIX_MC(ALshort
, X51Chans
, point16
)
550 DECL_MIX_MC(ALshort
, X51Chans
, lerp16
)
551 DECL_MIX_MC(ALshort
, X51Chans
, cos_lerp16
)
553 DECL_MIX_MC(ALubyte
, X51Chans
, point8
)
554 DECL_MIX_MC(ALubyte
, X51Chans
, lerp8
)
555 DECL_MIX_MC(ALubyte
, X51Chans
, cos_lerp8
)
558 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
561 SIDE_LEFT
, SIDE_RIGHT
};
562 DECL_MIX_MC(ALfloat
, X61Chans
, point32
)
563 DECL_MIX_MC(ALfloat
, X61Chans
, lerp32
)
564 DECL_MIX_MC(ALfloat
, X61Chans
, cos_lerp32
)
566 DECL_MIX_MC(ALshort
, X61Chans
, point16
)
567 DECL_MIX_MC(ALshort
, X61Chans
, lerp16
)
568 DECL_MIX_MC(ALshort
, X61Chans
, cos_lerp16
)
570 DECL_MIX_MC(ALubyte
, X61Chans
, point8
)
571 DECL_MIX_MC(ALubyte
, X61Chans
, lerp8
)
572 DECL_MIX_MC(ALubyte
, X61Chans
, cos_lerp8
)
575 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
577 BACK_LEFT
, BACK_RIGHT
,
578 SIDE_LEFT
, SIDE_RIGHT
};
579 DECL_MIX_MC(ALfloat
, X71Chans
, point32
)
580 DECL_MIX_MC(ALfloat
, X71Chans
, lerp32
)
581 DECL_MIX_MC(ALfloat
, X71Chans
, cos_lerp32
)
583 DECL_MIX_MC(ALshort
, X71Chans
, point16
)
584 DECL_MIX_MC(ALshort
, X71Chans
, lerp16
)
585 DECL_MIX_MC(ALshort
, X71Chans
, cos_lerp16
)
587 DECL_MIX_MC(ALubyte
, X71Chans
, point8
)
588 DECL_MIX_MC(ALubyte
, X71Chans
, lerp8
)
589 DECL_MIX_MC(ALubyte
, X71Chans
, cos_lerp8
)
592 #define DECL_MIX(T, sampler) \
593 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
594 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
595 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
600 MixMono_##T##_##sampler(Source, Device, \
601 Data, DataPosInt, DataPosFrac, \
602 j, SamplesToDo, BufferSize); \
604 case 2: /* Stereo */ \
605 MixStereo_##T##_##sampler(Source, Device, \
606 Data, DataPosInt, DataPosFrac, \
607 j, SamplesToDo, BufferSize); \
610 MixMC_##T##_QuadChans_##sampler(Source, Device, \
611 Data, DataPosInt, DataPosFrac, \
612 j, SamplesToDo, BufferSize); \
615 MixMC_##T##_X51Chans_##sampler(Source, Device, \
616 Data, DataPosInt, DataPosFrac, \
617 j, SamplesToDo, BufferSize); \
620 MixMC_##T##_X61Chans_##sampler(Source, Device, \
621 Data, DataPosInt, DataPosFrac, \
622 j, SamplesToDo, BufferSize); \
625 MixMC_##T##_X71Chans_##sampler(Source, Device, \
626 Data, DataPosInt, DataPosFrac, \
627 j, SamplesToDo, BufferSize); \
632 DECL_MIX(ALfloat
, point32
)
633 DECL_MIX(ALfloat
, lerp32
)
634 DECL_MIX(ALfloat
, cos_lerp32
)
636 DECL_MIX(ALshort
, point16
)
637 DECL_MIX(ALshort
, lerp16
)
638 DECL_MIX(ALshort
, cos_lerp16
)
640 DECL_MIX(ALubyte
, point8
)
641 DECL_MIX(ALubyte
, lerp8
)
642 DECL_MIX(ALubyte
, cos_lerp8
)
645 /* Stack data size can be whatever. Larger values need more stack, while
646 * smaller values may need more iterations */
647 #ifndef STACK_DATA_SIZE
648 #define STACK_DATA_SIZE 16384
651 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
653 ALbufferlistitem
*BufferListItem
;
654 ALuint FrameSize
, Channels
, Bytes
;
655 ALuint DataPosInt
, DataPosFrac
;
656 ALuint BuffersPlayed
;
663 /* Get source info */
664 State
= Source
->state
;
665 BuffersPlayed
= Source
->BuffersPlayed
;
666 DataPosInt
= Source
->position
;
667 DataPosFrac
= Source
->position_fraction
;
668 Looping
= Source
->bLooping
;
669 increment
= Source
->Params
.Step
;
671 /* Get buffer info */
672 FrameSize
= Channels
= Bytes
= 0;
673 BufferListItem
= Source
->queue
;
674 for(i
= 0;i
< Source
->BuffersInQueue
;i
++)
676 const ALbuffer
*ALBuffer
;
677 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
679 FrameSize
= aluFrameSizeFromFormat(ALBuffer
->format
);
680 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
681 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
684 BufferListItem
= BufferListItem
->next
;
687 /* Get current buffer queue item */
688 BufferListItem
= Source
->queue
;
689 for(i
= 0;i
< BuffersPlayed
;i
++)
690 BufferListItem
= BufferListItem
->next
;
694 ALubyte SrcData
[STACK_DATA_SIZE
];
695 ALuint SrcDataSize
= 0;
698 /* Figure out how many buffer bytes will be needed */
699 DataSize64
= SamplesToDo
-j
+1;
700 DataSize64
*= increment
;
701 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
702 DataSize64
>>= FRACTIONBITS
;
703 DataSize64
+= BUFFER_PADDING
;
704 DataSize64
*= FrameSize
;
706 BufferSize
= sizeof(SrcData
) - SrcDataSize
;
707 BufferSize
= min(DataSize64
, BufferSize
);
709 if(Source
->lSourceType
== AL_STATIC
)
711 const ALbuffer
*ALBuffer
= Source
->Buffer
;
712 const ALubyte
*Data
= ALBuffer
->data
;
715 /* If current pos is beyond the loop range, do not loop */
716 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
720 /* Copy what's left to play in the source buffer, and clear the
721 * rest of the temp buffer */
722 DataSize
= ALBuffer
->size
- DataPosInt
*FrameSize
;
723 DataSize
= min(BufferSize
, DataSize
);
725 memcpy(&SrcData
[SrcDataSize
], &Data
[DataPosInt
*FrameSize
], DataSize
);
726 SrcDataSize
+= DataSize
;
727 BufferSize
-= DataSize
;
729 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
730 SrcDataSize
+= BufferSize
;
731 BufferSize
-= BufferSize
;
735 ALuint LoopStart
= ALBuffer
->LoopStart
;
736 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
738 /* Copy what's left of this loop iteration, then copy repeats
739 * of the loop section */
740 DataSize
= (LoopEnd
-DataPosInt
) * FrameSize
;
741 DataSize
= min(BufferSize
, DataSize
);
743 memcpy(&SrcData
[SrcDataSize
], &Data
[DataPosInt
*FrameSize
], DataSize
);
744 SrcDataSize
+= DataSize
;
745 BufferSize
-= DataSize
;
747 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
748 while(BufferSize
> 0)
750 DataSize
= min(BufferSize
, DataSize
);
752 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
753 SrcDataSize
+= DataSize
;
754 BufferSize
-= DataSize
;
760 /* Crawl the buffer queue to fill in the temp buffer */
761 ALbufferlistitem
*BufferListIter
= BufferListItem
;
762 ALuint pos
= DataPosInt
*FrameSize
;
764 while(BufferListIter
&& BufferSize
> 0)
766 const ALbuffer
*ALBuffer
;
767 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
769 const ALubyte
*Data
= ALBuffer
->data
;
770 ALuint DataSize
= ALBuffer
->size
;
772 /* Skip the data already played */
781 DataSize
= min(BufferSize
, DataSize
);
782 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
783 SrcDataSize
+= DataSize
;
784 BufferSize
-= DataSize
;
787 BufferListIter
= BufferListIter
->next
;
788 if(!BufferListIter
&& Looping
)
789 BufferListIter
= Source
->queue
;
790 else if(!BufferListIter
)
792 memset(&SrcData
[SrcDataSize
], (Bytes
==1)?0x80:0, BufferSize
);
793 SrcDataSize
+= BufferSize
;
794 BufferSize
-= BufferSize
;
799 /* Figure out how many samples we can mix. */
800 DataSize64
= SrcDataSize
/ FrameSize
;
801 DataSize64
-= BUFFER_PADDING
;
802 DataSize64
<<= FRACTIONBITS
;
803 DataSize64
-= increment
;
805 BufferSize
= (ALuint
)((DataSize64
-DataPosFrac
+(increment
-1)) / increment
);
806 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
809 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
810 increment
, increment
/(double)(1<<FRACTIONBITS
));
812 BufferListItem
= Source
->queue
;
813 BuffersPlayed
= Source
->BuffersInQueue
;
819 switch(Source
->Resampler
)
821 case POINT_RESAMPLER
:
823 Mix_ALfloat_point32(Source
, Device
, Channels
,
824 SrcData
, &DataPosInt
, &DataPosFrac
,
825 j
, SamplesToDo
, BufferSize
);
827 Mix_ALshort_point16(Source
, Device
, Channels
,
828 SrcData
, &DataPosInt
, &DataPosFrac
,
829 j
, SamplesToDo
, BufferSize
);
831 Mix_ALubyte_point8(Source
, Device
, Channels
,
832 SrcData
, &DataPosInt
, &DataPosFrac
,
833 j
, SamplesToDo
, BufferSize
);
835 case LINEAR_RESAMPLER
:
837 Mix_ALfloat_lerp32(Source
, Device
, Channels
,
838 SrcData
, &DataPosInt
, &DataPosFrac
,
839 j
, SamplesToDo
, BufferSize
);
841 Mix_ALshort_lerp16(Source
, Device
, Channels
,
842 SrcData
, &DataPosInt
, &DataPosFrac
,
843 j
, SamplesToDo
, BufferSize
);
845 Mix_ALubyte_lerp8(Source
, Device
, Channels
,
846 SrcData
, &DataPosInt
, &DataPosFrac
,
847 j
, SamplesToDo
, BufferSize
);
849 case COSINE_RESAMPLER
:
851 Mix_ALfloat_cos_lerp32(Source
, Device
, Channels
,
852 SrcData
, &DataPosInt
, &DataPosFrac
,
853 j
, SamplesToDo
, BufferSize
);
855 Mix_ALshort_cos_lerp16(Source
, Device
, Channels
,
856 SrcData
, &DataPosInt
, &DataPosFrac
,
857 j
, SamplesToDo
, BufferSize
);
859 Mix_ALubyte_cos_lerp8(Source
, Device
, Channels
,
860 SrcData
, &DataPosInt
, &DataPosFrac
,
861 j
, SamplesToDo
, BufferSize
);
869 /* Handle looping sources */
872 const ALbuffer
*ALBuffer
;
874 ALuint LoopStart
= 0;
877 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
879 DataSize
= ALBuffer
->size
/ FrameSize
;
880 if(DataSize
> DataPosInt
)
882 LoopStart
= ALBuffer
->LoopStart
;
883 LoopEnd
= ALBuffer
->LoopEnd
;
886 if(BufferListItem
->next
)
888 BufferListItem
= BufferListItem
->next
;
893 BufferListItem
= Source
->queue
;
895 if(Source
->lSourceType
== AL_STATIC
)
897 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
904 BufferListItem
= Source
->queue
;
905 BuffersPlayed
= Source
->BuffersInQueue
;
911 DataPosInt
-= DataSize
;
913 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
915 /* Update source info */
916 Source
->state
= State
;
917 Source
->BuffersPlayed
= BuffersPlayed
;
918 Source
->position
= DataPosInt
;
919 Source
->position_fraction
= DataPosFrac
;
920 Source
->Buffer
= BufferListItem
->buffer
;