Always make sure there's a sample available to mix, for pending click removal
[openal-soft.git] / Alc / mixer.c
blob26c7f8de8bc896a7d9ab34623743ad0f2b7b2801
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;
74 static __inline ALfloat point8(ALfloat val1, ALfloat val2, ALint frac)
76 return (val1-128.0f) / 127.0f;
77 (void)val2;
78 (void)frac;
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) \
96 { \
97 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
98 ALfloat *ClickRemoval, *PendingClicks; \
99 ALuint pos, frac; \
100 ALfloat DrySend[OUTPUTCHANNELS]; \
101 FILTER *DryFilter; \
102 ALuint BufferIdx; \
103 ALuint increment; \
104 ALuint i, out; \
105 ALfloat value; \
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]; \
116 pos = 0; \
117 frac = *DataPosFrac; \
119 if(j == 0) \
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]; \
149 frac += increment; \
150 pos += frac>>FRACTIONBITS; \
151 frac &= FRACTIONMASK; \
152 j++; \
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++) \
171 ALfloat WetSend; \
172 ALfloat *WetBuffer; \
173 ALfloat *WetClickRemoval; \
174 ALfloat *WetPendingClicks; \
175 FILTER *WetFilter; \
177 if(!Source->Send[out].Slot || \
178 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
179 continue; \
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; \
187 pos = 0; \
188 frac = *DataPosFrac; \
189 j -= BufferSize; \
191 if(j == 0) \
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; \
207 frac += increment; \
208 pos += frac>>FRACTIONBITS; \
209 frac &= FRACTIONMASK; \
210 j++; \
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 \
247 }; \
248 const ALfloat scaler = 1.0f/Channels; \
249 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
250 ALfloat *ClickRemoval, *PendingClicks; \
251 ALuint pos, frac; \
252 ALfloat DrySend[OUTPUTCHANNELS]; \
253 FILTER *DryFilter; \
254 ALuint BufferIdx; \
255 ALuint increment; \
256 ALuint i, out; \
257 ALfloat value; \
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]; \
268 pos = 0; \
269 frac = *DataPosFrac; \
271 if(j == 0) \
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]]; \
297 frac += increment; \
298 pos += frac>>FRACTIONBITS; \
299 frac &= FRACTIONMASK; \
300 j++; \
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++) \
318 ALfloat WetSend; \
319 ALfloat *WetBuffer; \
320 ALfloat *WetClickRemoval; \
321 ALfloat *WetPendingClicks; \
322 FILTER *WetFilter; \
324 if(!Source->Send[out].Slot || \
325 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
326 continue; \
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; \
334 pos = 0; \
335 frac = *DataPosFrac; \
336 j -= BufferSize; \
338 if(j == 0) \
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; \
360 frac += increment; \
361 pos += frac>>FRACTIONBITS; \
362 frac &= FRACTIONMASK; \
363 j++; \
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; \
403 ALuint pos, frac; \
404 ALfloat DrySend[OUTPUTCHANNELS]; \
405 FILTER *DryFilter; \
406 ALuint BufferIdx; \
407 ALuint increment; \
408 ALuint i, out; \
409 ALfloat value; \
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]; \
420 pos = 0; \
421 frac = *DataPosFrac; \
423 if(j == 0) \
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]]; \
445 frac += increment; \
446 pos += frac>>FRACTIONBITS; \
447 frac &= FRACTIONMASK; \
448 j++; \
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++) \
464 ALfloat WetSend; \
465 ALfloat *WetBuffer; \
466 ALfloat *WetClickRemoval; \
467 ALfloat *WetPendingClicks; \
468 FILTER *WetFilter; \
470 if(!Source->Send[out].Slot || \
471 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
472 continue; \
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; \
480 pos = 0; \
481 frac = *DataPosFrac; \
482 j -= BufferSize; \
484 if(j == 0) \
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; \
506 frac += increment; \
507 pos += frac>>FRACTIONBITS; \
508 frac &= FRACTIONMASK; \
509 j++; \
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,
543 FRONT_CENTER, LFE,
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,
559 FRONT_CENTER, LFE,
560 BACK_CENTER,
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,
576 FRONT_CENTER, LFE,
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) \
597 switch(Channels) \
599 case 1: /* Mono */ \
600 MixMono_##T##_##sampler(Source, Device, \
601 Data, DataPosInt, DataPosFrac, \
602 j, SamplesToDo, BufferSize); \
603 break; \
604 case 2: /* Stereo */ \
605 MixStereo_##T##_##sampler(Source, Device, \
606 Data, DataPosInt, DataPosFrac, \
607 j, SamplesToDo, BufferSize); \
608 break; \
609 case 4: /* Quad */ \
610 MixMC_##T##_QuadChans_##sampler(Source, Device, \
611 Data, DataPosInt, DataPosFrac, \
612 j, SamplesToDo, BufferSize); \
613 break; \
614 case 6: /* 5.1 */ \
615 MixMC_##T##_X51Chans_##sampler(Source, Device, \
616 Data, DataPosInt, DataPosFrac, \
617 j, SamplesToDo, BufferSize); \
618 break; \
619 case 7: /* 6.1 */ \
620 MixMC_##T##_X61Chans_##sampler(Source, Device, \
621 Data, DataPosInt, DataPosFrac, \
622 j, SamplesToDo, BufferSize); \
623 break; \
624 case 8: /* 7.1 */ \
625 MixMC_##T##_X71Chans_##sampler(Source, Device, \
626 Data, DataPosInt, DataPosFrac, \
627 j, SamplesToDo, BufferSize); \
628 break; \
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
649 #endif
651 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
653 ALbufferlistitem *BufferListItem;
654 ALuint FrameSize, Channels, Bytes;
655 ALuint DataPosInt, DataPosFrac;
656 ALuint BuffersPlayed;
657 ALboolean Looping;
658 ALuint increment;
659 ALenum State;
660 ALuint i, j;
661 ALint64 DataSize64;
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);
682 break;
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;
692 j = 0;
693 do {
694 ALubyte SrcData[STACK_DATA_SIZE];
695 ALuint SrcDataSize = 0;
696 ALuint BufferSize;
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;
713 ALuint DataSize;
715 /* If current pos is beyond the loop range, do not loop */
716 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
718 Looping = AL_FALSE;
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;
733 else
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;
758 else
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 */
773 if(DataSize <= pos)
774 pos -= DataSize;
775 else
777 Data += pos;
778 DataSize -= pos;
779 pos -= pos;
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));
807 if(BufferSize == 0)
809 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
810 increment, increment/(double)(1<<FRACTIONBITS));
811 State = AL_STOPPED;
812 BufferListItem = Source->queue;
813 BuffersPlayed = Source->BuffersInQueue;
814 DataPosInt = 0;
815 DataPosFrac = 0;
816 break;
819 switch(Source->Resampler)
821 case POINT_RESAMPLER:
822 if(Bytes == 4)
823 Mix_ALfloat_point32(Source, Device, Channels,
824 SrcData, &DataPosInt, &DataPosFrac,
825 j, SamplesToDo, BufferSize);
826 else if(Bytes == 2)
827 Mix_ALshort_point16(Source, Device, Channels,
828 SrcData, &DataPosInt, &DataPosFrac,
829 j, SamplesToDo, BufferSize);
830 else if(Bytes == 1)
831 Mix_ALubyte_point8(Source, Device, Channels,
832 SrcData, &DataPosInt, &DataPosFrac,
833 j, SamplesToDo, BufferSize);
834 break;
835 case LINEAR_RESAMPLER:
836 if(Bytes == 4)
837 Mix_ALfloat_lerp32(Source, Device, Channels,
838 SrcData, &DataPosInt, &DataPosFrac,
839 j, SamplesToDo, BufferSize);
840 else if(Bytes == 2)
841 Mix_ALshort_lerp16(Source, Device, Channels,
842 SrcData, &DataPosInt, &DataPosFrac,
843 j, SamplesToDo, BufferSize);
844 else if(Bytes == 1)
845 Mix_ALubyte_lerp8(Source, Device, Channels,
846 SrcData, &DataPosInt, &DataPosFrac,
847 j, SamplesToDo, BufferSize);
848 break;
849 case COSINE_RESAMPLER:
850 if(Bytes == 4)
851 Mix_ALfloat_cos_lerp32(Source, Device, Channels,
852 SrcData, &DataPosInt, &DataPosFrac,
853 j, SamplesToDo, BufferSize);
854 else if(Bytes == 2)
855 Mix_ALshort_cos_lerp16(Source, Device, Channels,
856 SrcData, &DataPosInt, &DataPosFrac,
857 j, SamplesToDo, BufferSize);
858 else if(Bytes == 1)
859 Mix_ALubyte_cos_lerp8(Source, Device, Channels,
860 SrcData, &DataPosInt, &DataPosFrac,
861 j, SamplesToDo, BufferSize);
862 break;
863 case RESAMPLER_MIN:
864 case RESAMPLER_MAX:
865 break;
867 j += BufferSize;
869 /* Handle looping sources */
870 while(1)
872 const ALbuffer *ALBuffer;
873 ALuint DataSize = 0;
874 ALuint LoopStart = 0;
875 ALuint LoopEnd = 0;
877 if((ALBuffer=BufferListItem->buffer) != NULL)
879 DataSize = ALBuffer->size / FrameSize;
880 if(DataSize > DataPosInt)
881 break;
882 LoopStart = ALBuffer->LoopStart;
883 LoopEnd = ALBuffer->LoopEnd;
886 if(BufferListItem->next)
888 BufferListItem = BufferListItem->next;
889 BuffersPlayed++;
891 else if(Looping)
893 BufferListItem = Source->queue;
894 BuffersPlayed = 0;
895 if(Source->lSourceType == AL_STATIC)
897 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
898 break;
901 else
903 State = AL_STOPPED;
904 BufferListItem = Source->queue;
905 BuffersPlayed = Source->BuffersInQueue;
906 DataPosInt = 0;
907 DataPosFrac = 0;
908 break;
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;