Use simple loops instead of several explicit lines for the mono mixer
[openal-soft.git] / Alc / mixer.c
blob2ebce319d3bfc09125ead644da35204b1372740a
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 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) \
70 { \
71 ALfloat (*DryBuffer)[MAXCHANNELS]; \
72 ALfloat *ClickRemoval, *PendingClicks; \
73 ALuint pos, frac; \
74 ALfloat DrySend[MAXCHANNELS]; \
75 FILTER *DryFilter; \
76 ALuint BufferIdx; \
77 ALuint increment; \
78 ALuint i, out; \
79 ALfloat value; \
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 < MAXCHANNELS;i++) \
88 DrySend[i] = Source->Params.DryGains[i]; \
90 pos = 0; \
91 frac = *DataPosFrac; \
93 if(OutPos == 0) \
94 { \
95 value = sampler(data+pos, 1, frac); \
97 value = lpFilter4PC(DryFilter, 0, value); \
98 for(i = 0;i < MAXCHANNELS;i++) \
99 ClickRemoval[i] -= value*DrySend[i]; \
101 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
103 /* First order interpolator */ \
104 value = sampler(data+pos, 1, frac); \
106 /* Direct path final mix buffer and panning */ \
107 value = lpFilter4P(DryFilter, 0, value); \
108 for(i = 0;i < MAXCHANNELS;i++) \
109 DryBuffer[OutPos][i] += value*DrySend[i]; \
111 frac += increment; \
112 pos += frac>>FRACTIONBITS; \
113 frac &= FRACTIONMASK; \
114 OutPos++; \
116 if(OutPos == SamplesToDo) \
118 value = sampler(data+pos, 1, frac); \
120 value = lpFilter4PC(DryFilter, 0, value); \
121 for(i = 0;i < MAXCHANNELS;i++) \
122 PendingClicks[i] += value*DrySend[i]; \
125 for(out = 0;out < Device->NumAuxSends;out++) \
127 ALfloat WetSend; \
128 ALfloat *WetBuffer; \
129 ALfloat *WetClickRemoval; \
130 ALfloat *WetPendingClicks; \
131 FILTER *WetFilter; \
133 if(!Source->Send[out].Slot || \
134 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
135 continue; \
137 WetBuffer = Source->Send[out].Slot->WetBuffer; \
138 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
139 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
140 WetFilter = &Source->Params.Send[out].iirFilter; \
141 WetSend = Source->Params.Send[out].WetGain; \
143 pos = 0; \
144 frac = *DataPosFrac; \
145 OutPos -= BufferSize; \
147 if(OutPos == 0) \
149 value = sampler(data+pos, 1, frac); \
151 value = lpFilter2PC(WetFilter, 0, value); \
152 WetClickRemoval[0] -= value*WetSend; \
154 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
156 /* First order interpolator */ \
157 value = sampler(data+pos, 1, frac); \
159 /* Room path final mix buffer and panning */ \
160 value = lpFilter2P(WetFilter, 0, value); \
161 WetBuffer[OutPos] += value*WetSend; \
163 frac += increment; \
164 pos += frac>>FRACTIONBITS; \
165 frac &= FRACTIONMASK; \
166 OutPos++; \
168 if(OutPos == SamplesToDo) \
170 value = sampler(data+pos, 1, frac); \
172 value = lpFilter2PC(WetFilter, 0, value); \
173 WetPendingClicks[0] += value*WetSend; \
176 *DataPosInt += pos; \
177 *DataPosFrac = frac; \
180 DECL_TEMPLATE(ALfloat, point32)
181 DECL_TEMPLATE(ALfloat, lerp32)
182 DECL_TEMPLATE(ALfloat, cubic32)
184 DECL_TEMPLATE(ALshort, point16)
185 DECL_TEMPLATE(ALshort, lerp16)
186 DECL_TEMPLATE(ALshort, cubic16)
188 DECL_TEMPLATE(ALubyte, point8)
189 DECL_TEMPLATE(ALubyte, lerp8)
190 DECL_TEMPLATE(ALubyte, cubic8)
192 #undef DECL_TEMPLATE
195 #define DECL_TEMPLATE(T, sampler) \
196 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
197 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
198 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
200 static const ALuint Channels = 2; \
201 static const Channel chans[] = { \
202 FRONT_LEFT, FRONT_RIGHT, \
203 SIDE_LEFT, SIDE_RIGHT, \
204 BACK_LEFT, BACK_RIGHT \
205 }; \
206 const ALfloat scaler = 1.0f/Channels; \
207 ALfloat (*DryBuffer)[MAXCHANNELS]; \
208 ALfloat *ClickRemoval, *PendingClicks; \
209 ALuint pos, frac; \
210 ALfloat DrySend[MAXCHANNELS]; \
211 FILTER *DryFilter; \
212 ALuint BufferIdx; \
213 ALuint increment; \
214 ALuint i, out; \
215 ALfloat value; \
217 increment = Source->Params.Step; \
219 DryBuffer = Device->DryBuffer; \
220 ClickRemoval = Device->ClickRemoval; \
221 PendingClicks = Device->PendingClicks; \
222 DryFilter = &Source->Params.iirFilter; \
223 for(i = 0;i < MAXCHANNELS;i++) \
224 DrySend[i] = Source->Params.DryGains[i]; \
226 pos = 0; \
227 frac = *DataPosFrac; \
229 if(OutPos == 0) \
231 for(i = 0;i < Channels;i++) \
233 value = sampler(data + pos*Channels + i, Channels, frac); \
235 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
236 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
237 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
238 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
241 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
243 for(i = 0;i < Channels;i++) \
245 value = sampler(data + pos*Channels + i, Channels, frac); \
247 value = lpFilter2P(DryFilter, chans[i]*2, value); \
248 DryBuffer[OutPos][chans[i+0]] += value*DrySend[chans[i+0]]; \
249 DryBuffer[OutPos][chans[i+2]] += value*DrySend[chans[i+2]]; \
250 DryBuffer[OutPos][chans[i+4]] += value*DrySend[chans[i+4]]; \
253 frac += increment; \
254 pos += frac>>FRACTIONBITS; \
255 frac &= FRACTIONMASK; \
256 OutPos++; \
258 if(OutPos == SamplesToDo) \
260 for(i = 0;i < Channels;i++) \
262 value = sampler(data + pos*Channels + i, Channels, frac); \
264 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
265 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
266 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
267 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
271 for(out = 0;out < Device->NumAuxSends;out++) \
273 ALfloat WetSend; \
274 ALfloat *WetBuffer; \
275 ALfloat *WetClickRemoval; \
276 ALfloat *WetPendingClicks; \
277 FILTER *WetFilter; \
279 if(!Source->Send[out].Slot || \
280 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
281 continue; \
283 WetBuffer = Source->Send[out].Slot->WetBuffer; \
284 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
285 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
286 WetFilter = &Source->Params.Send[out].iirFilter; \
287 WetSend = Source->Params.Send[out].WetGain; \
289 pos = 0; \
290 frac = *DataPosFrac; \
291 OutPos -= BufferSize; \
293 if(OutPos == 0) \
295 for(i = 0;i < Channels;i++) \
297 value = sampler(data + pos*Channels + i, Channels, frac); \
299 value = lpFilter1PC(WetFilter, chans[i], value); \
300 WetClickRemoval[0] -= value*WetSend * scaler; \
303 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
305 for(i = 0;i < Channels;i++) \
307 value = sampler(data + pos*Channels + i, Channels, frac); \
309 value = lpFilter1P(WetFilter, chans[i], value); \
310 WetBuffer[OutPos] += value*WetSend * scaler; \
313 frac += increment; \
314 pos += frac>>FRACTIONBITS; \
315 frac &= FRACTIONMASK; \
316 OutPos++; \
318 if(OutPos == SamplesToDo) \
320 for(i = 0;i < Channels;i++) \
322 value = sampler(data + pos*Channels + i, Channels, frac); \
324 value = lpFilter1PC(WetFilter, chans[i], value); \
325 WetPendingClicks[0] += value*WetSend * scaler; \
329 *DataPosInt += pos; \
330 *DataPosFrac = frac; \
333 DECL_TEMPLATE(ALfloat, point32)
334 DECL_TEMPLATE(ALfloat, lerp32)
335 DECL_TEMPLATE(ALfloat, cubic32)
337 DECL_TEMPLATE(ALshort, point16)
338 DECL_TEMPLATE(ALshort, lerp16)
339 DECL_TEMPLATE(ALshort, cubic16)
341 DECL_TEMPLATE(ALubyte, point8)
342 DECL_TEMPLATE(ALubyte, lerp8)
343 DECL_TEMPLATE(ALubyte, cubic8)
345 #undef DECL_TEMPLATE
347 static const Channel RearChans[] = { BACK_LEFT, BACK_RIGHT };
348 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
349 BACK_LEFT, BACK_RIGHT };
350 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
351 FRONT_CENTER, LFE,
352 BACK_LEFT, BACK_RIGHT };
353 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_RIGHT,
354 FRONT_CENTER, LFE,
355 BACK_CENTER,
356 SIDE_LEFT, SIDE_RIGHT };
357 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
358 FRONT_CENTER, LFE,
359 BACK_LEFT, BACK_RIGHT,
360 SIDE_LEFT, SIDE_RIGHT };
362 #define DECL_TEMPLATE(T, count, sampler) \
363 static void Mix_##T##_##count##_##sampler(ALsource *Source, ALCdevice *Device,\
364 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
365 const Channel chans[count], \
366 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
368 const ALuint Channels = count; \
369 const ALfloat scaler = 1.0f/Channels; \
370 ALfloat (*DryBuffer)[MAXCHANNELS]; \
371 ALfloat *ClickRemoval, *PendingClicks; \
372 ALuint pos, frac; \
373 ALfloat DrySend[MAXCHANNELS]; \
374 FILTER *DryFilter; \
375 ALuint BufferIdx; \
376 ALuint increment; \
377 ALuint i, out; \
378 ALfloat value; \
380 increment = Source->Params.Step; \
382 DryBuffer = Device->DryBuffer; \
383 ClickRemoval = Device->ClickRemoval; \
384 PendingClicks = Device->PendingClicks; \
385 DryFilter = &Source->Params.iirFilter; \
386 for(i = 0;i < MAXCHANNELS;i++) \
387 DrySend[i] = Source->Params.DryGains[i]; \
389 pos = 0; \
390 frac = *DataPosFrac; \
392 if(OutPos == 0) \
394 for(i = 0;i < Channels;i++) \
396 value = sampler(data + pos*Channels + i, Channels, frac); \
398 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
399 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
402 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
404 for(i = 0;i < Channels;i++) \
406 value = sampler(data + pos*Channels + i, Channels, frac); \
408 value = lpFilter2P(DryFilter, chans[i]*2, value); \
409 DryBuffer[OutPos][chans[i]] += value*DrySend[chans[i]]; \
412 frac += increment; \
413 pos += frac>>FRACTIONBITS; \
414 frac &= FRACTIONMASK; \
415 OutPos++; \
417 if(OutPos == SamplesToDo) \
419 for(i = 0;i < Channels;i++) \
421 value = sampler(data + pos*Channels + i, Channels, frac); \
423 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
424 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
428 for(out = 0;out < Device->NumAuxSends;out++) \
430 ALfloat WetSend; \
431 ALfloat *WetBuffer; \
432 ALfloat *WetClickRemoval; \
433 ALfloat *WetPendingClicks; \
434 FILTER *WetFilter; \
436 if(!Source->Send[out].Slot || \
437 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
438 continue; \
440 WetBuffer = Source->Send[out].Slot->WetBuffer; \
441 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
442 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
443 WetFilter = &Source->Params.Send[out].iirFilter; \
444 WetSend = Source->Params.Send[out].WetGain; \
446 pos = 0; \
447 frac = *DataPosFrac; \
448 OutPos -= BufferSize; \
450 if(OutPos == 0) \
452 for(i = 0;i < Channels;i++) \
454 value = sampler(data + pos*Channels + i, Channels, frac); \
456 value = lpFilter1PC(WetFilter, chans[i], value); \
457 WetClickRemoval[0] -= value*WetSend * scaler; \
460 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
462 for(i = 0;i < Channels;i++) \
464 value = sampler(data + pos*Channels + i, Channels, frac); \
466 value = lpFilter1P(WetFilter, chans[i], value); \
467 WetBuffer[OutPos] += value*WetSend * scaler; \
470 frac += increment; \
471 pos += frac>>FRACTIONBITS; \
472 frac &= FRACTIONMASK; \
473 OutPos++; \
475 if(OutPos == SamplesToDo) \
477 for(i = 0;i < Channels;i++) \
479 value = sampler(data + pos*Channels + i, Channels, frac); \
481 value = lpFilter1PC(WetFilter, chans[i], value); \
482 WetPendingClicks[0] += value*WetSend * scaler; \
486 *DataPosInt += pos; \
487 *DataPosFrac = frac; \
490 DECL_TEMPLATE(ALfloat, 2, point32)
491 DECL_TEMPLATE(ALfloat, 2, lerp32)
492 DECL_TEMPLATE(ALfloat, 2, cubic32)
494 DECL_TEMPLATE(ALshort, 2, point16)
495 DECL_TEMPLATE(ALshort, 2, lerp16)
496 DECL_TEMPLATE(ALshort, 2, cubic16)
498 DECL_TEMPLATE(ALubyte, 2, point8)
499 DECL_TEMPLATE(ALubyte, 2, lerp8)
500 DECL_TEMPLATE(ALubyte, 2, cubic8)
503 DECL_TEMPLATE(ALfloat, 4, point32)
504 DECL_TEMPLATE(ALfloat, 4, lerp32)
505 DECL_TEMPLATE(ALfloat, 4, cubic32)
507 DECL_TEMPLATE(ALshort, 4, point16)
508 DECL_TEMPLATE(ALshort, 4, lerp16)
509 DECL_TEMPLATE(ALshort, 4, cubic16)
511 DECL_TEMPLATE(ALubyte, 4, point8)
512 DECL_TEMPLATE(ALubyte, 4, lerp8)
513 DECL_TEMPLATE(ALubyte, 4, cubic8)
516 DECL_TEMPLATE(ALfloat, 6, point32)
517 DECL_TEMPLATE(ALfloat, 6, lerp32)
518 DECL_TEMPLATE(ALfloat, 6, cubic32)
520 DECL_TEMPLATE(ALshort, 6, point16)
521 DECL_TEMPLATE(ALshort, 6, lerp16)
522 DECL_TEMPLATE(ALshort, 6, cubic16)
524 DECL_TEMPLATE(ALubyte, 6, point8)
525 DECL_TEMPLATE(ALubyte, 6, lerp8)
526 DECL_TEMPLATE(ALubyte, 6, cubic8)
529 DECL_TEMPLATE(ALfloat, 7, point32)
530 DECL_TEMPLATE(ALfloat, 7, lerp32)
531 DECL_TEMPLATE(ALfloat, 7, cubic32)
533 DECL_TEMPLATE(ALshort, 7, point16)
534 DECL_TEMPLATE(ALshort, 7, lerp16)
535 DECL_TEMPLATE(ALshort, 7, cubic16)
537 DECL_TEMPLATE(ALubyte, 7, point8)
538 DECL_TEMPLATE(ALubyte, 7, lerp8)
539 DECL_TEMPLATE(ALubyte, 7, cubic8)
542 DECL_TEMPLATE(ALfloat, 8, point32)
543 DECL_TEMPLATE(ALfloat, 8, lerp32)
544 DECL_TEMPLATE(ALfloat, 8, cubic32)
546 DECL_TEMPLATE(ALshort, 8, point16)
547 DECL_TEMPLATE(ALshort, 8, lerp16)
548 DECL_TEMPLATE(ALshort, 8, cubic16)
550 DECL_TEMPLATE(ALubyte, 8, point8)
551 DECL_TEMPLATE(ALubyte, 8, lerp8)
552 DECL_TEMPLATE(ALubyte, 8, cubic8)
554 #undef DECL_TEMPLATE
557 #define DECL_TEMPLATE(T, sampler) \
558 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
559 enum FmtChannels FmtChannels, \
560 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
561 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
563 switch(FmtChannels) \
565 case FmtMono: \
566 Mix_##T##_Mono_##sampler(Source, Device, \
567 Data, DataPosInt, DataPosFrac, \
568 OutPos, SamplesToDo, BufferSize); \
569 break; \
570 case FmtStereo: \
571 Mix_##T##_Stereo_##sampler(Source, Device, \
572 Data, DataPosInt, DataPosFrac, \
573 OutPos, SamplesToDo, BufferSize); \
574 break; \
575 case FmtQuad: \
576 Mix_##T##_4_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
577 QuadChans, OutPos, SamplesToDo, BufferSize); \
578 break; \
579 case FmtRear: \
580 Mix_##T##_2_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
581 RearChans, OutPos, SamplesToDo, BufferSize); \
582 break; \
583 case FmtX51: \
584 Mix_##T##_6_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
585 X51Chans, OutPos, SamplesToDo, BufferSize); \
586 break; \
587 case FmtX61: \
588 Mix_##T##_7_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
589 X61Chans, OutPos, SamplesToDo, BufferSize); \
590 break; \
591 case FmtX71: \
592 Mix_##T##_8_##sampler(Source, Device, Data, DataPosInt, DataPosFrac, \
593 X71Chans, OutPos, SamplesToDo, BufferSize); \
594 break; \
598 DECL_TEMPLATE(ALfloat, point32)
599 DECL_TEMPLATE(ALfloat, lerp32)
600 DECL_TEMPLATE(ALfloat, cubic32)
602 DECL_TEMPLATE(ALshort, point16)
603 DECL_TEMPLATE(ALshort, lerp16)
604 DECL_TEMPLATE(ALshort, cubic16)
606 DECL_TEMPLATE(ALubyte, point8)
607 DECL_TEMPLATE(ALubyte, lerp8)
608 DECL_TEMPLATE(ALubyte, cubic8)
610 #undef DECL_TEMPLATE
613 #define DECL_TEMPLATE(sampler) \
614 static void Mix_##sampler(ALsource *Source, ALCdevice *Device, \
615 enum FmtChannels FmtChannels, enum FmtType FmtType, \
616 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
617 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
619 switch(FmtType) \
621 case FmtUByte: \
622 Mix_ALubyte_##sampler##8(Source, Device, FmtChannels, \
623 Data, DataPosInt, DataPosFrac, \
624 OutPos, SamplesToDo, BufferSize); \
625 break; \
627 case FmtShort: \
628 Mix_ALshort_##sampler##16(Source, Device, FmtChannels, \
629 Data, DataPosInt, DataPosFrac, \
630 OutPos, SamplesToDo, BufferSize); \
631 break; \
633 case FmtFloat: \
634 Mix_ALfloat_##sampler##32(Source, Device, FmtChannels, \
635 Data, DataPosInt, DataPosFrac, \
636 OutPos, SamplesToDo, BufferSize); \
637 break; \
641 DECL_TEMPLATE(point)
642 DECL_TEMPLATE(lerp)
643 DECL_TEMPLATE(cubic)
645 #undef DECL_TEMPLATE
648 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
650 ALbufferlistitem *BufferListItem;
651 ALuint DataPosInt, DataPosFrac;
652 enum FmtChannels FmtChannels;
653 enum FmtType FmtType;
654 ALuint BuffersPlayed;
655 ALboolean Looping;
656 ALuint increment;
657 resampler_t Resampler;
658 ALenum State;
659 ALuint OutPos;
660 ALuint FrameSize;
661 ALint64 DataSize64;
662 ALuint i;
664 /* Get source info */
665 State = Source->state;
666 BuffersPlayed = Source->BuffersPlayed;
667 DataPosInt = Source->position;
668 DataPosFrac = Source->position_fraction;
669 Looping = Source->bLooping;
670 increment = Source->Params.Step;
671 Resampler = (increment == FRACTIONONE) ? POINT_RESAMPLER :
672 Source->Resampler;
674 /* Get buffer info */
675 FrameSize = 0;
676 FmtChannels = FmtMono;
677 FmtType = FmtUByte;
678 BufferListItem = Source->queue;
679 for(i = 0;i < Source->BuffersInQueue;i++)
681 const ALbuffer *ALBuffer;
682 if((ALBuffer=BufferListItem->buffer) != NULL)
684 FmtChannels = ALBuffer->FmtChannels;
685 FmtType = ALBuffer->FmtType;
686 FrameSize = FrameSizeFromFmt(FmtChannels, FmtType);
687 break;
689 BufferListItem = BufferListItem->next;
692 /* Get current buffer queue item */
693 BufferListItem = Source->queue;
694 for(i = 0;i < BuffersPlayed;i++)
695 BufferListItem = BufferListItem->next;
697 OutPos = 0;
698 do {
699 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
700 const ALuint BufferPadding = ResamplerPadding[Resampler];
701 ALubyte StackData[STACK_DATA_SIZE];
702 ALubyte *SrcData = StackData;
703 ALuint SrcDataSize = 0;
704 ALuint BufferSize;
706 /* Figure out how many buffer bytes will be needed */
707 DataSize64 = SamplesToDo-OutPos+1;
708 DataSize64 *= increment;
709 DataSize64 += DataPosFrac+FRACTIONMASK;
710 DataSize64 >>= FRACTIONBITS;
711 DataSize64 += BufferPadding+BufferPrePadding;
712 DataSize64 *= FrameSize;
714 BufferSize = min(DataSize64, STACK_DATA_SIZE);
715 BufferSize -= BufferSize%FrameSize;
717 if(Source->lSourceType == AL_STATIC)
719 const ALbuffer *ALBuffer = Source->Buffer;
720 const ALubyte *Data = ALBuffer->data;
721 ALuint DataSize;
722 ALuint pos;
724 /* If current pos is beyond the loop range, do not loop */
725 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
727 Looping = AL_FALSE;
729 if(DataPosInt >= BufferPrePadding)
730 pos = (DataPosInt-BufferPrePadding)*FrameSize;
731 else
733 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
734 DataSize = min(BufferSize, DataSize);
736 memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
737 SrcDataSize += DataSize;
738 BufferSize -= DataSize;
740 pos = 0;
743 /* Copy what's left to play in the source buffer, and clear the
744 * rest of the temp buffer */
745 DataSize = ALBuffer->size - pos;
746 DataSize = min(BufferSize, DataSize);
748 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
749 SrcDataSize += DataSize;
750 BufferSize -= DataSize;
752 memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
753 SrcDataSize += BufferSize;
754 BufferSize -= BufferSize;
756 else
758 ALuint LoopStart = ALBuffer->LoopStart;
759 ALuint LoopEnd = ALBuffer->LoopEnd;
761 if(DataPosInt >= LoopStart)
763 pos = DataPosInt-LoopStart;
764 while(pos < BufferPrePadding)
765 pos += LoopEnd-LoopStart;
766 pos -= BufferPrePadding;
767 pos += LoopStart;
768 pos *= FrameSize;
770 else if(DataPosInt >= BufferPrePadding)
771 pos = (DataPosInt-BufferPrePadding)*FrameSize;
772 else
774 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
775 DataSize = min(BufferSize, DataSize);
777 memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
778 SrcDataSize += DataSize;
779 BufferSize -= DataSize;
781 pos = 0;
784 /* Copy what's left of this loop iteration, then copy repeats
785 * of the loop section */
786 DataSize = LoopEnd*FrameSize - pos;
787 DataSize = min(BufferSize, DataSize);
789 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
790 SrcDataSize += DataSize;
791 BufferSize -= DataSize;
793 DataSize = (LoopEnd-LoopStart) * FrameSize;
794 while(BufferSize > 0)
796 DataSize = min(BufferSize, DataSize);
798 memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
799 SrcDataSize += DataSize;
800 BufferSize -= DataSize;
804 else
806 /* Crawl the buffer queue to fill in the temp buffer */
807 ALbufferlistitem *BufferListIter = BufferListItem;
808 ALuint pos;
810 if(DataPosInt >= BufferPrePadding)
811 pos = (DataPosInt-BufferPrePadding)*FrameSize;
812 else
814 pos = (BufferPrePadding-DataPosInt)*FrameSize;
815 while(pos > 0)
817 if(!BufferListIter->prev && !Looping)
819 ALuint DataSize = min(BufferSize, pos);
821 memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
822 SrcDataSize += DataSize;
823 BufferSize -= DataSize;
825 pos = 0;
826 break;
829 if(Looping)
831 while(BufferListIter->next)
832 BufferListIter = BufferListIter->next;
834 else
835 BufferListIter = BufferListIter->prev;
837 if(BufferListIter->buffer)
839 if((ALuint)BufferListIter->buffer->size > pos)
841 pos = BufferListIter->buffer->size - pos;
842 break;
844 pos -= BufferListIter->buffer->size;
849 while(BufferListIter && BufferSize > 0)
851 const ALbuffer *ALBuffer;
852 if((ALBuffer=BufferListIter->buffer) != NULL)
854 const ALubyte *Data = ALBuffer->data;
855 ALuint DataSize = ALBuffer->size;
857 /* Skip the data already played */
858 if(DataSize <= pos)
859 pos -= DataSize;
860 else
862 Data += pos;
863 DataSize -= pos;
864 pos -= pos;
866 DataSize = min(BufferSize, DataSize);
867 memcpy(&SrcData[SrcDataSize], Data, DataSize);
868 SrcDataSize += DataSize;
869 BufferSize -= DataSize;
872 BufferListIter = BufferListIter->next;
873 if(!BufferListIter && Looping)
874 BufferListIter = Source->queue;
875 else if(!BufferListIter)
877 memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
878 SrcDataSize += BufferSize;
879 BufferSize -= BufferSize;
884 /* Figure out how many samples we can mix. */
885 DataSize64 = SrcDataSize / FrameSize;
886 DataSize64 -= BufferPadding+BufferPrePadding;
887 DataSize64 <<= FRACTIONBITS;
888 DataSize64 -= increment;
889 DataSize64 -= DataPosFrac;
891 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
892 BufferSize = min(BufferSize, (SamplesToDo-OutPos));
894 SrcData += BufferPrePadding*FrameSize;
895 switch(Resampler)
897 case POINT_RESAMPLER:
898 Mix_point(Source, Device, FmtChannels, FmtType,
899 SrcData, &DataPosInt, &DataPosFrac,
900 OutPos, SamplesToDo, BufferSize);
901 break;
902 case LINEAR_RESAMPLER:
903 Mix_lerp(Source, Device, FmtChannels, FmtType,
904 SrcData, &DataPosInt, &DataPosFrac,
905 OutPos, SamplesToDo, BufferSize);
906 break;
907 case CUBIC_RESAMPLER:
908 Mix_cubic(Source, Device, FmtChannels, FmtType,
909 SrcData, &DataPosInt, &DataPosFrac,
910 OutPos, SamplesToDo, BufferSize);
911 break;
912 case RESAMPLER_MIN:
913 case RESAMPLER_MAX:
914 break;
916 OutPos += BufferSize;
918 /* Handle looping sources */
919 while(1)
921 const ALbuffer *ALBuffer;
922 ALuint DataSize = 0;
923 ALuint LoopStart = 0;
924 ALuint LoopEnd = 0;
926 if((ALBuffer=BufferListItem->buffer) != NULL)
928 DataSize = ALBuffer->size / FrameSize;
929 if(DataSize > DataPosInt)
930 break;
931 LoopStart = ALBuffer->LoopStart;
932 LoopEnd = ALBuffer->LoopEnd;
935 if(BufferListItem->next)
937 BufferListItem = BufferListItem->next;
938 BuffersPlayed++;
940 else if(Looping)
942 BufferListItem = Source->queue;
943 BuffersPlayed = 0;
944 if(Source->lSourceType == AL_STATIC)
946 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
947 break;
950 else
952 State = AL_STOPPED;
953 BufferListItem = Source->queue;
954 BuffersPlayed = Source->BuffersInQueue;
955 DataPosInt = 0;
956 DataPosFrac = 0;
957 break;
960 DataPosInt -= DataSize;
962 } while(State == AL_PLAYING && OutPos < SamplesToDo);
964 /* Update source info */
965 Source->state = State;
966 Source->BuffersPlayed = BuffersPlayed;
967 Source->position = DataPosInt;
968 Source->position_fraction = DataPosFrac;
969 Source->Buffer = BufferListItem->buffer;