Check the sample byte size after the resampler
[openal-soft.git] / Alc / mixer.c
blob35b8653ba39aa4e9f14f8852f5b5fd07b4b6bd9a
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.h"
40 static __inline ALfloat point32(ALfloat val1, ALfloat val2, ALint frac)
42 return val1;
43 (void)val2;
44 (void)frac;
46 static __inline ALfloat lerp32(ALfloat val1, ALfloat val2, ALint frac)
48 val1 += ((val2-val1) * (frac * (1.0/(1<<FRACTIONBITS))));
49 return val1;
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));
54 return val1;
57 static __inline ALfloat point16(ALfloat val1, ALfloat val2, ALint frac)
59 return val1 / 32767.0f;
60 (void)val2;
61 (void)frac;
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;
75 #define DECL_MIX_MONO(T,sampler) \
76 static void MixMono_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
77 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
78 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
79 { \
80 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
81 ALfloat *ClickRemoval, *PendingClicks; \
82 ALuint pos, frac; \
83 ALfloat DrySend[OUTPUTCHANNELS]; \
84 FILTER *DryFilter; \
85 ALuint BufferIdx; \
86 ALuint increment; \
87 ALuint i, out; \
88 ALfloat value; \
90 increment = Source->Params.Step; \
92 DryBuffer = Device->DryBuffer; \
93 ClickRemoval = Device->ClickRemoval; \
94 PendingClicks = Device->PendingClicks; \
95 DryFilter = &Source->Params.iirFilter; \
96 for(i = 0;i < OUTPUTCHANNELS;i++) \
97 DrySend[i] = Source->Params.DryGains[i]; \
99 pos = *DataPosInt; \
100 frac = *DataPosFrac; \
102 if(j == 0) \
104 value = sampler(data[pos], data[pos+1], frac); \
106 value = lpFilter4PC(DryFilter, 0, value); \
107 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
108 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
109 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
110 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
111 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
112 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
113 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
114 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
116 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
118 /* First order interpolator */ \
119 value = sampler(data[pos], data[pos+1], frac); \
121 /* Direct path final mix buffer and panning */ \
122 value = lpFilter4P(DryFilter, 0, value); \
123 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
124 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
125 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
126 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
127 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
128 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
129 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
130 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
132 frac += increment; \
133 pos += frac>>FRACTIONBITS; \
134 frac &= FRACTIONMASK; \
135 j++; \
137 if(j == SamplesToDo) \
139 ALuint p = pos; \
140 ALuint f = frac; \
141 if(p >= DataEnd) \
143 ALuint64 pos64 = pos; \
144 pos64 <<= FRACTIONBITS; \
145 pos64 += frac; \
146 pos64 -= increment; \
147 p = pos64>>FRACTIONBITS; \
148 f = pos64&FRACTIONMASK; \
150 value = sampler(data[p], data[p+1], f); \
152 value = lpFilter4PC(DryFilter, 0, value); \
153 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
154 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
155 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
156 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
157 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
158 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
159 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
160 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
163 for(out = 0;out < Device->NumAuxSends;out++) \
165 ALfloat WetSend; \
166 ALfloat *WetBuffer; \
167 ALfloat *WetClickRemoval; \
168 ALfloat *WetPendingClicks; \
169 FILTER *WetFilter; \
171 if(!Source->Send[out].Slot || \
172 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
173 continue; \
175 WetBuffer = Source->Send[out].Slot->WetBuffer; \
176 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
177 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
178 WetFilter = &Source->Params.Send[out].iirFilter; \
179 WetSend = Source->Params.Send[out].WetGain; \
181 pos = *DataPosInt; \
182 frac = *DataPosFrac; \
183 j -= BufferSize; \
185 if(j == 0) \
187 value = sampler(data[pos], data[pos+1], frac); \
189 value = lpFilter2PC(WetFilter, 0, value); \
190 WetClickRemoval[0] -= value*WetSend; \
192 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
194 /* First order interpolator */ \
195 value = sampler(data[pos], data[pos+1], frac); \
197 /* Room path final mix buffer and panning */ \
198 value = lpFilter2P(WetFilter, 0, value); \
199 WetBuffer[j] += value*WetSend; \
201 frac += increment; \
202 pos += frac>>FRACTIONBITS; \
203 frac &= FRACTIONMASK; \
204 j++; \
206 if(j == SamplesToDo) \
208 ALuint p = pos; \
209 ALuint f = frac; \
210 if(p >= DataEnd) \
212 ALuint64 pos64 = pos; \
213 pos64 <<= FRACTIONBITS; \
214 pos64 += frac; \
215 pos64 -= increment; \
216 p = pos64>>FRACTIONBITS; \
217 f = pos64&FRACTIONMASK; \
219 value = sampler(data[p], data[p+1], f); \
221 value = lpFilter2PC(WetFilter, 0, value); \
222 WetPendingClicks[0] += value*WetSend; \
225 *DataPosInt = pos; \
226 *DataPosFrac = frac; \
229 DECL_MIX_MONO(ALfloat, point32)
230 DECL_MIX_MONO(ALfloat, lerp32)
231 DECL_MIX_MONO(ALfloat, cos_lerp32)
233 DECL_MIX_MONO(ALshort, point16)
234 DECL_MIX_MONO(ALshort, lerp16)
235 DECL_MIX_MONO(ALshort, cos_lerp16)
238 #define DECL_MIX_STEREO(T,sampler) \
239 static void MixStereo_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
240 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
241 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
243 static const ALuint Channels = 2; \
244 static const Channel chans[] = { \
245 FRONT_LEFT, FRONT_RIGHT, \
246 SIDE_LEFT, SIDE_RIGHT, \
247 BACK_LEFT, BACK_RIGHT \
248 }; \
249 const ALfloat scaler = 1.0f/Channels; \
250 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
251 ALfloat *ClickRemoval, *PendingClicks; \
252 ALuint pos, frac; \
253 ALfloat DrySend[OUTPUTCHANNELS]; \
254 FILTER *DryFilter; \
255 ALuint BufferIdx; \
256 ALuint increment; \
257 ALuint i, out; \
258 ALfloat value; \
260 increment = Source->Params.Step; \
262 DryBuffer = Device->DryBuffer; \
263 ClickRemoval = Device->ClickRemoval; \
264 PendingClicks = Device->PendingClicks; \
265 DryFilter = &Source->Params.iirFilter; \
266 for(i = 0;i < OUTPUTCHANNELS;i++) \
267 DrySend[i] = Source->Params.DryGains[i]; \
269 pos = *DataPosInt; \
270 frac = *DataPosFrac; \
272 if(j == 0) \
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 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
281 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
282 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
285 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
287 for(i = 0;i < Channels;i++) \
289 value = sampler(data[pos*Channels + i], \
290 data[(pos+1)*Channels + i], frac); \
292 value = lpFilter2P(DryFilter, chans[i]*2, value); \
293 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
294 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
295 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
298 frac += increment; \
299 pos += frac>>FRACTIONBITS; \
300 frac &= FRACTIONMASK; \
301 j++; \
303 if(j == SamplesToDo) \
305 ALuint p = pos; \
306 ALuint f = frac; \
307 if(p >= DataEnd) \
309 ALuint64 pos64 = pos; \
310 pos64 <<= FRACTIONBITS; \
311 pos64 += frac; \
312 pos64 -= increment; \
313 p = pos64>>FRACTIONBITS; \
314 f = pos64&FRACTIONMASK; \
316 for(i = 0;i < Channels;i++) \
318 value = sampler(data[p*Channels + i], \
319 data[(p+1)*Channels + i], f); \
321 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
322 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
323 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
324 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
328 for(out = 0;out < Device->NumAuxSends;out++) \
330 ALfloat WetSend; \
331 ALfloat *WetBuffer; \
332 ALfloat *WetClickRemoval; \
333 ALfloat *WetPendingClicks; \
334 FILTER *WetFilter; \
336 if(!Source->Send[out].Slot || \
337 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
338 continue; \
340 WetBuffer = Source->Send[out].Slot->WetBuffer; \
341 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
342 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
343 WetFilter = &Source->Params.Send[out].iirFilter; \
344 WetSend = Source->Params.Send[out].WetGain; \
346 pos = *DataPosInt; \
347 frac = *DataPosFrac; \
348 j -= BufferSize; \
350 if(j == 0) \
352 for(i = 0;i < Channels;i++) \
354 value = sampler(data[pos*Channels + i], \
355 data[(pos+1)*Channels + i], frac); \
357 value = lpFilter1PC(WetFilter, chans[i], value); \
358 WetClickRemoval[0] -= value*WetSend * scaler; \
361 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
363 for(i = 0;i < Channels;i++) \
365 value = sampler(data[pos*Channels + i], \
366 data[(pos+1)*Channels + i], frac); \
368 value = lpFilter1P(WetFilter, chans[i], value); \
369 WetBuffer[j] += value*WetSend * scaler; \
372 frac += increment; \
373 pos += frac>>FRACTIONBITS; \
374 frac &= FRACTIONMASK; \
375 j++; \
377 if(j == SamplesToDo) \
379 ALuint p = pos; \
380 ALuint f = frac; \
381 if(p >= DataEnd) \
383 ALuint64 pos64 = pos; \
384 pos64 <<= FRACTIONBITS; \
385 pos64 += frac; \
386 pos64 -= increment; \
387 p = pos64>>FRACTIONBITS; \
388 f = pos64&FRACTIONMASK; \
390 for(i = 0;i < Channels;i++) \
392 value = sampler(data[p*Channels + i], \
393 data[(p+1)*Channels + i], f); \
395 value = lpFilter1PC(WetFilter, chans[i], value); \
396 WetPendingClicks[0] += value*WetSend * scaler; \
400 *DataPosInt = pos; \
401 *DataPosFrac = frac; \
404 DECL_MIX_STEREO(ALfloat, point32)
405 DECL_MIX_STEREO(ALfloat, lerp32)
406 DECL_MIX_STEREO(ALfloat, cos_lerp32)
408 DECL_MIX_STEREO(ALshort, point16)
409 DECL_MIX_STEREO(ALshort, lerp16)
410 DECL_MIX_STEREO(ALshort, cos_lerp16)
414 #define DECL_MIX_MC(T,chans,sampler) \
415 static void MixMC_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
416 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd, \
417 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
419 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
420 const ALfloat scaler = 1.0f/Channels; \
421 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
422 ALfloat *ClickRemoval, *PendingClicks; \
423 ALuint pos, frac; \
424 ALfloat DrySend[OUTPUTCHANNELS]; \
425 FILTER *DryFilter; \
426 ALuint BufferIdx; \
427 ALuint increment; \
428 ALuint i, out; \
429 ALfloat value; \
431 increment = Source->Params.Step; \
433 DryBuffer = Device->DryBuffer; \
434 ClickRemoval = Device->ClickRemoval; \
435 PendingClicks = Device->PendingClicks; \
436 DryFilter = &Source->Params.iirFilter; \
437 for(i = 0;i < OUTPUTCHANNELS;i++) \
438 DrySend[i] = Source->Params.DryGains[i]; \
440 pos = *DataPosInt; \
441 frac = *DataPosFrac; \
443 if(j == 0) \
445 for(i = 0;i < Channels;i++) \
447 value = sampler(data[pos*Channels + i], \
448 data[(pos+1)*Channels + i], frac); \
450 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
451 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
454 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
456 for(i = 0;i < Channels;i++) \
458 value = sampler(data[pos*Channels + i], \
459 data[(pos+1)*Channels + i], frac); \
461 value = lpFilter2P(DryFilter, chans[i]*2, value); \
462 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
465 frac += increment; \
466 pos += frac>>FRACTIONBITS; \
467 frac &= FRACTIONMASK; \
468 j++; \
470 if(j == SamplesToDo) \
472 ALuint p = pos; \
473 ALuint f = frac; \
474 if(p >= DataEnd) \
476 ALuint64 pos64 = pos; \
477 pos64 <<= FRACTIONBITS; \
478 pos64 += frac; \
479 pos64 -= increment; \
480 p = pos64>>FRACTIONBITS; \
481 f = pos64&FRACTIONMASK; \
483 for(i = 0;i < Channels;i++) \
485 value = sampler(data[p*Channels + i], \
486 data[(p+1)*Channels + i], f); \
488 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
489 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
493 for(out = 0;out < Device->NumAuxSends;out++) \
495 ALfloat WetSend; \
496 ALfloat *WetBuffer; \
497 ALfloat *WetClickRemoval; \
498 ALfloat *WetPendingClicks; \
499 FILTER *WetFilter; \
501 if(!Source->Send[out].Slot || \
502 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
503 continue; \
505 WetBuffer = Source->Send[out].Slot->WetBuffer; \
506 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
507 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
508 WetFilter = &Source->Params.Send[out].iirFilter; \
509 WetSend = Source->Params.Send[out].WetGain; \
511 pos = *DataPosInt; \
512 frac = *DataPosFrac; \
513 j -= BufferSize; \
515 if(j == 0) \
517 for(i = 0;i < Channels;i++) \
519 value = sampler(data[pos*Channels + i], \
520 data[(pos+1)*Channels + i], frac); \
522 value = lpFilter1PC(WetFilter, chans[i], value); \
523 WetClickRemoval[0] -= value*WetSend * scaler; \
526 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
528 for(i = 0;i < Channels;i++) \
530 value = sampler(data[pos*Channels + i], \
531 data[(pos+1)*Channels + i], frac); \
533 value = lpFilter1P(WetFilter, chans[i], value); \
534 WetBuffer[j] += value*WetSend * scaler; \
537 frac += increment; \
538 pos += frac>>FRACTIONBITS; \
539 frac &= FRACTIONMASK; \
540 j++; \
542 if(j == SamplesToDo) \
544 ALuint p = pos; \
545 ALuint f = frac; \
546 if(p >= DataEnd) \
548 ALuint64 pos64 = pos; \
549 pos64 <<= FRACTIONBITS; \
550 pos64 += frac; \
551 pos64 -= increment; \
552 p = pos64>>FRACTIONBITS; \
553 f = pos64&FRACTIONMASK; \
555 for(i = 0;i < Channels;i++) \
557 value = sampler(data[p*Channels + i], \
558 data[(p+1)*Channels + i], f); \
560 value = lpFilter1PC(WetFilter, chans[i], value); \
561 WetPendingClicks[0] += value*WetSend * scaler; \
565 *DataPosInt = pos; \
566 *DataPosFrac = frac; \
569 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
570 BACK_LEFT, BACK_RIGHT };
571 DECL_MIX_MC(ALfloat, QuadChans, point32)
572 DECL_MIX_MC(ALfloat, QuadChans, lerp32)
573 DECL_MIX_MC(ALfloat, QuadChans, cos_lerp32)
575 DECL_MIX_MC(ALshort, QuadChans, point16)
576 DECL_MIX_MC(ALshort, QuadChans, lerp16)
577 DECL_MIX_MC(ALshort, QuadChans, cos_lerp16)
580 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
581 FRONT_CENTER, LFE,
582 BACK_LEFT, BACK_RIGHT };
583 DECL_MIX_MC(ALfloat, X51Chans, point32)
584 DECL_MIX_MC(ALfloat, X51Chans, lerp32)
585 DECL_MIX_MC(ALfloat, X51Chans, cos_lerp32)
587 DECL_MIX_MC(ALshort, X51Chans, point16)
588 DECL_MIX_MC(ALshort, X51Chans, lerp16)
589 DECL_MIX_MC(ALshort, X51Chans, cos_lerp16)
592 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_RIGHT,
593 FRONT_CENTER, LFE,
594 BACK_CENTER,
595 SIDE_LEFT, SIDE_RIGHT };
596 DECL_MIX_MC(ALfloat, X61Chans, point32)
597 DECL_MIX_MC(ALfloat, X61Chans, lerp32)
598 DECL_MIX_MC(ALfloat, X61Chans, cos_lerp32)
600 DECL_MIX_MC(ALshort, X61Chans, point16)
601 DECL_MIX_MC(ALshort, X61Chans, lerp16)
602 DECL_MIX_MC(ALshort, X61Chans, cos_lerp16)
605 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
606 FRONT_CENTER, LFE,
607 BACK_LEFT, BACK_RIGHT,
608 SIDE_LEFT, SIDE_RIGHT };
609 DECL_MIX_MC(ALfloat, X71Chans, point32)
610 DECL_MIX_MC(ALfloat, X71Chans, lerp32)
611 DECL_MIX_MC(ALfloat, X71Chans, cos_lerp32)
613 DECL_MIX_MC(ALshort, X71Chans, point16)
614 DECL_MIX_MC(ALshort, X71Chans, lerp16)
615 DECL_MIX_MC(ALshort, X71Chans, cos_lerp16)
618 #define DECL_MIX(T, sampler) \
619 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
620 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, ALuint DataEnd,\
621 ALuint j, ALuint SamplesToDo, ALuint BufferSize) \
623 switch(Channels) \
625 case 1: /* Mono */ \
626 MixMono_##T##_##sampler(Source, Device, \
627 Data, DataPosInt, DataPosFrac, DataEnd, \
628 j, SamplesToDo, BufferSize); \
629 break; \
630 case 2: /* Stereo */ \
631 MixStereo_##T##_##sampler(Source, Device, \
632 Data, DataPosInt, DataPosFrac, DataEnd, \
633 j, SamplesToDo, BufferSize); \
634 break; \
635 case 4: /* Quad */ \
636 MixMC_##T##_QuadChans_##sampler(Source, Device, \
637 Data, DataPosInt, DataPosFrac, DataEnd, \
638 j, SamplesToDo, BufferSize); \
639 break; \
640 case 6: /* 5.1 */ \
641 MixMC_##T##_X51Chans_##sampler(Source, Device, \
642 Data, DataPosInt, DataPosFrac, DataEnd, \
643 j, SamplesToDo, BufferSize); \
644 break; \
645 case 7: /* 6.1 */ \
646 MixMC_##T##_X61Chans_##sampler(Source, Device, \
647 Data, DataPosInt, DataPosFrac, DataEnd, \
648 j, SamplesToDo, BufferSize); \
649 break; \
650 case 8: /* 7.1 */ \
651 MixMC_##T##_X71Chans_##sampler(Source, Device, \
652 Data, DataPosInt, DataPosFrac, DataEnd, \
653 j, SamplesToDo, BufferSize); \
654 break; \
658 DECL_MIX(ALfloat, point32)
659 DECL_MIX(ALfloat, lerp32)
660 DECL_MIX(ALfloat, cos_lerp32)
662 DECL_MIX(ALshort, point16)
663 DECL_MIX(ALshort, lerp16)
664 DECL_MIX(ALshort, cos_lerp16)
667 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
669 ALbufferlistitem *BufferListItem;
670 ALint64 DataSize64,DataPos64;
671 ALint increment;
672 ALuint DataPosInt, DataPosFrac;
673 ALuint BuffersPlayed;
674 ALboolean Looping;
675 ALenum State;
676 ALuint i, j;
678 /* Get source info */
679 State = Source->state;
680 BuffersPlayed = Source->BuffersPlayed;
681 DataPosInt = Source->position;
682 DataPosFrac = Source->position_fraction;
683 Looping = Source->bLooping;
685 /* Get current buffer queue item */
686 BufferListItem = Source->queue;
687 for(i = 0;i < BuffersPlayed;i++)
688 BufferListItem = BufferListItem->next;
690 j = 0;
691 do {
692 const ALbuffer *ALBuffer;
693 ALubyte *Data = NULL;
694 ALuint DataSize = 0;
695 ALuint LoopStart = 0;
696 ALuint LoopEnd = 0;
697 ALuint Channels, Bytes;
698 ALuint BufferSize;
700 /* Get buffer info */
701 if((ALBuffer=BufferListItem->buffer) != NULL)
703 Data = ALBuffer->data;
704 DataSize = ALBuffer->size;
705 DataSize /= aluFrameSizeFromFormat(ALBuffer->format);
706 Channels = aluChannelsFromFormat(ALBuffer->format);
707 Bytes = aluBytesFromFormat(ALBuffer->format);
709 LoopStart = 0;
710 LoopEnd = DataSize;
711 if(Looping && Source->lSourceType == AL_STATIC)
713 /* If current pos is beyond the loop range, do not loop */
714 if(DataPosInt >= LoopEnd)
715 Looping = AL_FALSE;
716 else
718 LoopStart = ALBuffer->LoopStart;
719 LoopEnd = ALBuffer->LoopEnd;
724 if(DataPosInt >= DataSize)
725 goto skipmix;
727 memset(&Data[DataSize*Channels*Bytes], 0, BUFFER_PADDING*Channels*Bytes);
728 if(BufferListItem->next)
730 ALbuffer *NextBuf = BufferListItem->next->buffer;
731 if(NextBuf && NextBuf->size)
733 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
734 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
735 memcpy(&Data[DataSize*Channels*Bytes],
736 NextBuf->data, ulExtraSamples);
739 else if(Looping)
741 ALbuffer *NextBuf = Source->queue->buffer;
742 if(NextBuf && NextBuf->size)
744 ALint ulExtraSamples = BUFFER_PADDING*Channels*Bytes;
745 ulExtraSamples = min(NextBuf->size, ulExtraSamples);
746 memcpy(&Data[DataSize*Channels*Bytes],
747 &((ALubyte*)NextBuf->data)[LoopStart*Channels*Bytes],
748 ulExtraSamples);
752 /* Figure out how many samples we can mix. */
753 increment = Source->Params.Step;
754 DataSize64 = LoopEnd;
755 DataSize64 <<= FRACTIONBITS;
756 DataPos64 = DataPosInt;
757 DataPos64 <<= FRACTIONBITS;
758 DataPos64 += DataPosFrac;
759 BufferSize = (ALuint)((DataSize64-DataPos64+(increment-1)) / increment);
761 BufferSize = min(BufferSize, (SamplesToDo-j));
763 switch(Source->Resampler)
765 case POINT_RESAMPLER:
766 if(Bytes == 4)
767 Mix_ALfloat_point32(Source, Device, Channels,
768 Data, &DataPosInt, &DataPosFrac, LoopEnd,
769 j, SamplesToDo, BufferSize);
770 else if(Bytes == 2)
771 Mix_ALshort_point16(Source, Device, Channels,
772 Data, &DataPosInt, &DataPosFrac, LoopEnd,
773 j, SamplesToDo, BufferSize);
774 break;
775 case LINEAR_RESAMPLER:
776 if(Bytes == 4)
777 Mix_ALfloat_lerp32(Source, Device, Channels,
778 Data, &DataPosInt, &DataPosFrac, LoopEnd,
779 j, SamplesToDo, BufferSize);
780 else if(Bytes == 2)
781 Mix_ALshort_lerp16(Source, Device, Channels,
782 Data, &DataPosInt, &DataPosFrac, LoopEnd,
783 j, SamplesToDo, BufferSize);
784 break;
785 case COSINE_RESAMPLER:
786 if(Bytes == 4)
787 Mix_ALfloat_cos_lerp32(Source, Device, Channels,
788 Data, &DataPosInt, &DataPosFrac, LoopEnd,
789 j, SamplesToDo, BufferSize);
790 else if(Bytes == 2)
791 Mix_ALshort_cos_lerp16(Source, Device, Channels,
792 Data, &DataPosInt, &DataPosFrac, LoopEnd,
793 j, SamplesToDo, BufferSize);
794 break;
795 case RESAMPLER_MIN:
796 case RESAMPLER_MAX:
797 break;
799 j += BufferSize;
801 skipmix:
802 /* Handle looping sources */
803 if(DataPosInt >= LoopEnd)
805 if(BufferListItem->next)
807 BufferListItem = BufferListItem->next;
808 BuffersPlayed++;
809 DataPosInt -= DataSize;
811 else if(Looping)
813 BufferListItem = Source->queue;
814 BuffersPlayed = 0;
815 if(Source->lSourceType == AL_STATIC)
816 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
817 else
818 DataPosInt -= DataSize;
820 else
822 State = AL_STOPPED;
823 BufferListItem = Source->queue;
824 BuffersPlayed = Source->BuffersInQueue;
825 DataPosInt = 0;
826 DataPosFrac = 0;
829 } while(State == AL_PLAYING && j < SamplesToDo);
831 /* Update source info */
832 Source->state = State;
833 Source->BuffersPlayed = BuffersPlayed;
834 Source->position = DataPosInt;
835 Source->position_fraction = DataPosFrac;
836 Source->Buffer = BufferListItem->buffer;