Rename some variables to be clearer
[openal-soft.git] / Alc / mixer.c
blobb1ad0771e24b493fa6d723693e655a796dfd684e
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)[OUTPUTCHANNELS]; \
72 ALfloat *ClickRemoval, *PendingClicks; \
73 ALuint pos, frac; \
74 ALfloat DrySend[OUTPUTCHANNELS]; \
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 < OUTPUTCHANNELS;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 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
99 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
100 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
101 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
102 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
103 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
104 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
105 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
107 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
109 /* First order interpolator */ \
110 value = sampler(data+pos, 1, frac); \
112 /* Direct path final mix buffer and panning */ \
113 value = lpFilter4P(DryFilter, 0, value); \
114 DryBuffer[OutPos][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
115 DryBuffer[OutPos][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
116 DryBuffer[OutPos][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
117 DryBuffer[OutPos][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
118 DryBuffer[OutPos][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
119 DryBuffer[OutPos][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
120 DryBuffer[OutPos][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
121 DryBuffer[OutPos][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
123 frac += increment; \
124 pos += frac>>FRACTIONBITS; \
125 frac &= FRACTIONMASK; \
126 OutPos++; \
128 if(OutPos == SamplesToDo) \
130 value = sampler(data+pos, 1, frac); \
132 value = lpFilter4PC(DryFilter, 0, value); \
133 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
134 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
135 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
136 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
137 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
138 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
139 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
140 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
143 for(out = 0;out < Device->NumAuxSends;out++) \
145 ALfloat WetSend; \
146 ALfloat *WetBuffer; \
147 ALfloat *WetClickRemoval; \
148 ALfloat *WetPendingClicks; \
149 FILTER *WetFilter; \
151 if(!Source->Send[out].Slot || \
152 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
153 continue; \
155 WetBuffer = Source->Send[out].Slot->WetBuffer; \
156 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
157 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
158 WetFilter = &Source->Params.Send[out].iirFilter; \
159 WetSend = Source->Params.Send[out].WetGain; \
161 pos = 0; \
162 frac = *DataPosFrac; \
163 OutPos -= BufferSize; \
165 if(OutPos == 0) \
167 value = sampler(data+pos, 1, frac); \
169 value = lpFilter2PC(WetFilter, 0, value); \
170 WetClickRemoval[0] -= value*WetSend; \
172 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
174 /* First order interpolator */ \
175 value = sampler(data+pos, 1, frac); \
177 /* Room path final mix buffer and panning */ \
178 value = lpFilter2P(WetFilter, 0, value); \
179 WetBuffer[OutPos] += value*WetSend; \
181 frac += increment; \
182 pos += frac>>FRACTIONBITS; \
183 frac &= FRACTIONMASK; \
184 OutPos++; \
186 if(OutPos == SamplesToDo) \
188 value = sampler(data+pos, 1, frac); \
190 value = lpFilter2PC(WetFilter, 0, value); \
191 WetPendingClicks[0] += value*WetSend; \
194 *DataPosInt += pos; \
195 *DataPosFrac = frac; \
198 DECL_TEMPLATE(ALfloat, point32)
199 DECL_TEMPLATE(ALfloat, lerp32)
200 DECL_TEMPLATE(ALfloat, cubic32)
202 DECL_TEMPLATE(ALshort, point16)
203 DECL_TEMPLATE(ALshort, lerp16)
204 DECL_TEMPLATE(ALshort, cubic16)
206 DECL_TEMPLATE(ALubyte, point8)
207 DECL_TEMPLATE(ALubyte, lerp8)
208 DECL_TEMPLATE(ALubyte, cubic8)
210 #undef DECL_TEMPLATE
213 #define DECL_TEMPLATE(T, sampler) \
214 static void Mix_##T##_Stereo_##sampler(ALsource *Source, ALCdevice *Device, \
215 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
216 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
218 static const ALuint Channels = 2; \
219 static const Channel chans[] = { \
220 FRONT_LEFT, FRONT_RIGHT, \
221 SIDE_LEFT, SIDE_RIGHT, \
222 BACK_LEFT, BACK_RIGHT \
223 }; \
224 const ALfloat scaler = 1.0f/Channels; \
225 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
226 ALfloat *ClickRemoval, *PendingClicks; \
227 ALuint pos, frac; \
228 ALfloat DrySend[OUTPUTCHANNELS]; \
229 FILTER *DryFilter; \
230 ALuint BufferIdx; \
231 ALuint increment; \
232 ALuint i, out; \
233 ALfloat value; \
235 increment = Source->Params.Step; \
237 DryBuffer = Device->DryBuffer; \
238 ClickRemoval = Device->ClickRemoval; \
239 PendingClicks = Device->PendingClicks; \
240 DryFilter = &Source->Params.iirFilter; \
241 for(i = 0;i < OUTPUTCHANNELS;i++) \
242 DrySend[i] = Source->Params.DryGains[i]; \
244 pos = 0; \
245 frac = *DataPosFrac; \
247 if(OutPos == 0) \
249 for(i = 0;i < Channels;i++) \
251 value = sampler(data + pos*Channels + i, Channels, frac); \
253 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
254 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
255 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
256 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
259 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
261 for(i = 0;i < Channels;i++) \
263 value = sampler(data + pos*Channels + i, Channels, frac); \
265 value = lpFilter2P(DryFilter, chans[i]*2, value); \
266 DryBuffer[OutPos][chans[i+0]] += value*DrySend[chans[i+0]]; \
267 DryBuffer[OutPos][chans[i+2]] += value*DrySend[chans[i+2]]; \
268 DryBuffer[OutPos][chans[i+4]] += value*DrySend[chans[i+4]]; \
271 frac += increment; \
272 pos += frac>>FRACTIONBITS; \
273 frac &= FRACTIONMASK; \
274 OutPos++; \
276 if(OutPos == SamplesToDo) \
278 for(i = 0;i < Channels;i++) \
280 value = sampler(data + pos*Channels + i, Channels, frac); \
282 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
283 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
284 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
285 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
289 for(out = 0;out < Device->NumAuxSends;out++) \
291 ALfloat WetSend; \
292 ALfloat *WetBuffer; \
293 ALfloat *WetClickRemoval; \
294 ALfloat *WetPendingClicks; \
295 FILTER *WetFilter; \
297 if(!Source->Send[out].Slot || \
298 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
299 continue; \
301 WetBuffer = Source->Send[out].Slot->WetBuffer; \
302 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
303 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
304 WetFilter = &Source->Params.Send[out].iirFilter; \
305 WetSend = Source->Params.Send[out].WetGain; \
307 pos = 0; \
308 frac = *DataPosFrac; \
309 OutPos -= BufferSize; \
311 if(OutPos == 0) \
313 for(i = 0;i < Channels;i++) \
315 value = sampler(data + pos*Channels + i, Channels, frac); \
317 value = lpFilter1PC(WetFilter, chans[i], value); \
318 WetClickRemoval[0] -= value*WetSend * scaler; \
321 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
323 for(i = 0;i < Channels;i++) \
325 value = sampler(data + pos*Channels + i, Channels, frac); \
327 value = lpFilter1P(WetFilter, chans[i], value); \
328 WetBuffer[OutPos] += value*WetSend * scaler; \
331 frac += increment; \
332 pos += frac>>FRACTIONBITS; \
333 frac &= FRACTIONMASK; \
334 OutPos++; \
336 if(OutPos == SamplesToDo) \
338 for(i = 0;i < Channels;i++) \
340 value = sampler(data + pos*Channels + i, Channels, frac); \
342 value = lpFilter1PC(WetFilter, chans[i], value); \
343 WetPendingClicks[0] += value*WetSend * scaler; \
347 *DataPosInt += pos; \
348 *DataPosFrac = frac; \
351 DECL_TEMPLATE(ALfloat, point32)
352 DECL_TEMPLATE(ALfloat, lerp32)
353 DECL_TEMPLATE(ALfloat, cubic32)
355 DECL_TEMPLATE(ALshort, point16)
356 DECL_TEMPLATE(ALshort, lerp16)
357 DECL_TEMPLATE(ALshort, cubic16)
359 DECL_TEMPLATE(ALubyte, point8)
360 DECL_TEMPLATE(ALubyte, lerp8)
361 DECL_TEMPLATE(ALubyte, cubic8)
363 #undef DECL_TEMPLATE
366 #define DECL_TEMPLATE(T, chans, sampler) \
367 static void Mix_##T##_##chans##_##sampler(ALsource *Source, ALCdevice *Device,\
368 const T *data, ALuint *DataPosInt, ALuint *DataPosFrac, \
369 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
371 static const ALuint Channels = sizeof(chans)/sizeof(chans[0]); \
372 const ALfloat scaler = 1.0f/Channels; \
373 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
374 ALfloat *ClickRemoval, *PendingClicks; \
375 ALuint pos, frac; \
376 ALfloat DrySend[OUTPUTCHANNELS]; \
377 FILTER *DryFilter; \
378 ALuint BufferIdx; \
379 ALuint increment; \
380 ALuint i, out; \
381 ALfloat value; \
383 increment = Source->Params.Step; \
385 DryBuffer = Device->DryBuffer; \
386 ClickRemoval = Device->ClickRemoval; \
387 PendingClicks = Device->PendingClicks; \
388 DryFilter = &Source->Params.iirFilter; \
389 for(i = 0;i < OUTPUTCHANNELS;i++) \
390 DrySend[i] = Source->Params.DryGains[i]; \
392 pos = 0; \
393 frac = *DataPosFrac; \
395 if(OutPos == 0) \
397 for(i = 0;i < Channels;i++) \
399 value = sampler(data + pos*Channels + i, Channels, frac); \
401 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
402 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
405 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
407 for(i = 0;i < Channels;i++) \
409 value = sampler(data + pos*Channels + i, Channels, frac); \
411 value = lpFilter2P(DryFilter, chans[i]*2, value); \
412 DryBuffer[OutPos][chans[i]] += value*DrySend[chans[i]]; \
415 frac += increment; \
416 pos += frac>>FRACTIONBITS; \
417 frac &= FRACTIONMASK; \
418 OutPos++; \
420 if(OutPos == SamplesToDo) \
422 for(i = 0;i < Channels;i++) \
424 value = sampler(data + pos*Channels + i, Channels, frac); \
426 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
427 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
431 for(out = 0;out < Device->NumAuxSends;out++) \
433 ALfloat WetSend; \
434 ALfloat *WetBuffer; \
435 ALfloat *WetClickRemoval; \
436 ALfloat *WetPendingClicks; \
437 FILTER *WetFilter; \
439 if(!Source->Send[out].Slot || \
440 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
441 continue; \
443 WetBuffer = Source->Send[out].Slot->WetBuffer; \
444 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
445 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
446 WetFilter = &Source->Params.Send[out].iirFilter; \
447 WetSend = Source->Params.Send[out].WetGain; \
449 pos = 0; \
450 frac = *DataPosFrac; \
451 OutPos -= BufferSize; \
453 if(OutPos == 0) \
455 for(i = 0;i < Channels;i++) \
457 value = sampler(data + pos*Channels + i, Channels, frac); \
459 value = lpFilter1PC(WetFilter, chans[i], value); \
460 WetClickRemoval[0] -= value*WetSend * scaler; \
463 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
465 for(i = 0;i < Channels;i++) \
467 value = sampler(data + pos*Channels + i, Channels, frac); \
469 value = lpFilter1P(WetFilter, chans[i], value); \
470 WetBuffer[OutPos] += value*WetSend * scaler; \
473 frac += increment; \
474 pos += frac>>FRACTIONBITS; \
475 frac &= FRACTIONMASK; \
476 OutPos++; \
478 if(OutPos == SamplesToDo) \
480 for(i = 0;i < Channels;i++) \
482 value = sampler(data + pos*Channels + i, Channels, frac); \
484 value = lpFilter1PC(WetFilter, chans[i], value); \
485 WetPendingClicks[0] += value*WetSend * scaler; \
489 *DataPosInt += pos; \
490 *DataPosFrac = frac; \
493 static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
494 BACK_LEFT, BACK_RIGHT };
495 DECL_TEMPLATE(ALfloat, QuadChans, point32)
496 DECL_TEMPLATE(ALfloat, QuadChans, lerp32)
497 DECL_TEMPLATE(ALfloat, QuadChans, cubic32)
499 DECL_TEMPLATE(ALshort, QuadChans, point16)
500 DECL_TEMPLATE(ALshort, QuadChans, lerp16)
501 DECL_TEMPLATE(ALshort, QuadChans, cubic16)
503 DECL_TEMPLATE(ALubyte, QuadChans, point8)
504 DECL_TEMPLATE(ALubyte, QuadChans, lerp8)
505 DECL_TEMPLATE(ALubyte, QuadChans, cubic8)
508 static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
509 FRONT_CENTER, LFE,
510 BACK_LEFT, BACK_RIGHT };
511 DECL_TEMPLATE(ALfloat, X51Chans, point32)
512 DECL_TEMPLATE(ALfloat, X51Chans, lerp32)
513 DECL_TEMPLATE(ALfloat, X51Chans, cubic32)
515 DECL_TEMPLATE(ALshort, X51Chans, point16)
516 DECL_TEMPLATE(ALshort, X51Chans, lerp16)
517 DECL_TEMPLATE(ALshort, X51Chans, cubic16)
519 DECL_TEMPLATE(ALubyte, X51Chans, point8)
520 DECL_TEMPLATE(ALubyte, X51Chans, lerp8)
521 DECL_TEMPLATE(ALubyte, X51Chans, cubic8)
524 static const Channel X61Chans[] = { FRONT_LEFT, FRONT_RIGHT,
525 FRONT_CENTER, LFE,
526 BACK_CENTER,
527 SIDE_LEFT, SIDE_RIGHT };
528 DECL_TEMPLATE(ALfloat, X61Chans, point32)
529 DECL_TEMPLATE(ALfloat, X61Chans, lerp32)
530 DECL_TEMPLATE(ALfloat, X61Chans, cubic32)
532 DECL_TEMPLATE(ALshort, X61Chans, point16)
533 DECL_TEMPLATE(ALshort, X61Chans, lerp16)
534 DECL_TEMPLATE(ALshort, X61Chans, cubic16)
536 DECL_TEMPLATE(ALubyte, X61Chans, point8)
537 DECL_TEMPLATE(ALubyte, X61Chans, lerp8)
538 DECL_TEMPLATE(ALubyte, X61Chans, cubic8)
541 static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
542 FRONT_CENTER, LFE,
543 BACK_LEFT, BACK_RIGHT,
544 SIDE_LEFT, SIDE_RIGHT };
545 DECL_TEMPLATE(ALfloat, X71Chans, point32)
546 DECL_TEMPLATE(ALfloat, X71Chans, lerp32)
547 DECL_TEMPLATE(ALfloat, X71Chans, cubic32)
549 DECL_TEMPLATE(ALshort, X71Chans, point16)
550 DECL_TEMPLATE(ALshort, X71Chans, lerp16)
551 DECL_TEMPLATE(ALshort, X71Chans, cubic16)
553 DECL_TEMPLATE(ALubyte, X71Chans, point8)
554 DECL_TEMPLATE(ALubyte, X71Chans, lerp8)
555 DECL_TEMPLATE(ALubyte, X71Chans, cubic8)
557 #undef DECL_TEMPLATE
560 #define DECL_TEMPLATE(T, sampler) \
561 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, ALuint Channels, \
562 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
563 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
565 switch(Channels) \
567 case 1: /* Mono */ \
568 Mix_##T##_Mono_##sampler(Source, Device, \
569 Data, DataPosInt, DataPosFrac, \
570 OutPos, SamplesToDo, BufferSize); \
571 break; \
572 case 2: /* Stereo */ \
573 Mix_##T##_Stereo_##sampler(Source, Device, \
574 Data, DataPosInt, DataPosFrac, \
575 OutPos, SamplesToDo, BufferSize); \
576 break; \
577 case 4: /* Quad */ \
578 Mix_##T##_QuadChans_##sampler(Source, Device, \
579 Data, DataPosInt, DataPosFrac, \
580 OutPos, SamplesToDo, BufferSize); \
581 break; \
582 case 6: /* 5.1 */ \
583 Mix_##T##_X51Chans_##sampler(Source, Device, \
584 Data, DataPosInt, DataPosFrac, \
585 OutPos, SamplesToDo, BufferSize); \
586 break; \
587 case 7: /* 6.1 */ \
588 Mix_##T##_X61Chans_##sampler(Source, Device, \
589 Data, DataPosInt, DataPosFrac, \
590 OutPos, SamplesToDo, BufferSize); \
591 break; \
592 case 8: /* 7.1 */ \
593 Mix_##T##_X71Chans_##sampler(Source, Device, \
594 Data, DataPosInt, DataPosFrac, \
595 OutPos, SamplesToDo, BufferSize); \
596 break; \
600 DECL_TEMPLATE(ALfloat, point32)
601 DECL_TEMPLATE(ALfloat, lerp32)
602 DECL_TEMPLATE(ALfloat, cubic32)
604 DECL_TEMPLATE(ALshort, point16)
605 DECL_TEMPLATE(ALshort, lerp16)
606 DECL_TEMPLATE(ALshort, cubic16)
608 DECL_TEMPLATE(ALubyte, point8)
609 DECL_TEMPLATE(ALubyte, lerp8)
610 DECL_TEMPLATE(ALubyte, cubic8)
612 #undef DECL_TEMPLATE
615 /* Stack data size can be whatever. Larger values need more stack, while
616 * smaller values may need more iterations */
617 #ifndef STACK_DATA_SIZE
618 #define STACK_DATA_SIZE 16384
619 #endif
621 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
623 ALbufferlistitem *BufferListItem;
624 ALuint FrameSize, Channels, Bytes;
625 ALuint DataPosInt, DataPosFrac;
626 ALuint BuffersPlayed;
627 ALboolean Looping;
628 ALuint increment;
629 resampler_t Resampler;
630 ALenum State;
631 ALuint OutPos;
632 ALuint i;
633 ALint64 DataSize64;
635 /* Get source info */
636 State = Source->state;
637 BuffersPlayed = Source->BuffersPlayed;
638 DataPosInt = Source->position;
639 DataPosFrac = Source->position_fraction;
640 Looping = Source->bLooping;
641 increment = Source->Params.Step;
642 Resampler = (increment == FRACTIONONE) ? POINT_RESAMPLER :
643 Source->Resampler;
645 /* Get buffer info */
646 FrameSize = Channels = Bytes = 0;
647 BufferListItem = Source->queue;
648 for(i = 0;i < Source->BuffersInQueue;i++)
650 const ALbuffer *ALBuffer;
651 if((ALBuffer=BufferListItem->buffer) != NULL)
653 FrameSize = aluFrameSizeFromFormat(ALBuffer->format);
654 Channels = aluChannelsFromFormat(ALBuffer->format);
655 Bytes = aluBytesFromFormat(ALBuffer->format);
656 break;
658 BufferListItem = BufferListItem->next;
661 /* Get current buffer queue item */
662 BufferListItem = Source->queue;
663 for(i = 0;i < BuffersPlayed;i++)
664 BufferListItem = BufferListItem->next;
666 OutPos = 0;
667 do {
668 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
669 const ALuint BufferPadding = ResamplerPadding[Resampler];
670 ALubyte StackData[STACK_DATA_SIZE];
671 ALubyte *SrcData = StackData;
672 ALuint SrcDataSize = 0;
673 ALuint BufferSize;
675 /* Figure out how many buffer bytes will be needed */
676 DataSize64 = SamplesToDo-OutPos+1;
677 DataSize64 *= increment;
678 DataSize64 += DataPosFrac+FRACTIONMASK;
679 DataSize64 >>= FRACTIONBITS;
680 DataSize64 += BufferPadding+BufferPrePadding;
681 DataSize64 *= FrameSize;
683 BufferSize = min(DataSize64, STACK_DATA_SIZE);
684 BufferSize -= BufferSize%FrameSize;
686 if(Source->lSourceType == AL_STATIC)
688 const ALbuffer *ALBuffer = Source->Buffer;
689 const ALubyte *Data = ALBuffer->data;
690 ALuint DataSize;
691 ALuint pos;
693 /* If current pos is beyond the loop range, do not loop */
694 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
696 Looping = AL_FALSE;
698 if(DataPosInt >= BufferPrePadding)
699 pos = (DataPosInt-BufferPrePadding)*FrameSize;
700 else
702 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
703 DataSize = min(BufferSize, DataSize);
705 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
706 SrcDataSize += DataSize;
707 BufferSize -= DataSize;
709 pos = 0;
712 /* Copy what's left to play in the source buffer, and clear the
713 * rest of the temp buffer */
714 DataSize = ALBuffer->size - pos;
715 DataSize = min(BufferSize, DataSize);
717 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
718 SrcDataSize += DataSize;
719 BufferSize -= DataSize;
721 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
722 SrcDataSize += BufferSize;
723 BufferSize -= BufferSize;
725 else
727 ALuint LoopStart = ALBuffer->LoopStart;
728 ALuint LoopEnd = ALBuffer->LoopEnd;
730 if(DataPosInt >= LoopStart)
732 pos = DataPosInt-LoopStart;
733 while(pos < BufferPrePadding)
734 pos += LoopEnd-LoopStart;
735 pos -= BufferPrePadding;
736 pos += LoopStart;
737 pos *= FrameSize;
739 else if(DataPosInt >= BufferPrePadding)
740 pos = (DataPosInt-BufferPrePadding)*FrameSize;
741 else
743 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
744 DataSize = min(BufferSize, DataSize);
746 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
747 SrcDataSize += DataSize;
748 BufferSize -= DataSize;
750 pos = 0;
753 /* Copy what's left of this loop iteration, then copy repeats
754 * of the loop section */
755 DataSize = LoopEnd*FrameSize - pos;
756 DataSize = min(BufferSize, DataSize);
758 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
759 SrcDataSize += DataSize;
760 BufferSize -= DataSize;
762 DataSize = (LoopEnd-LoopStart) * FrameSize;
763 while(BufferSize > 0)
765 DataSize = min(BufferSize, DataSize);
767 memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
768 SrcDataSize += DataSize;
769 BufferSize -= DataSize;
773 else
775 /* Crawl the buffer queue to fill in the temp buffer */
776 ALbufferlistitem *BufferListIter = BufferListItem;
777 ALuint pos;
779 if(DataPosInt >= BufferPrePadding)
780 pos = (DataPosInt-BufferPrePadding)*FrameSize;
781 else
783 pos = (BufferPrePadding-DataPosInt)*FrameSize;
784 while(pos > 0)
786 if(!BufferListIter->prev && !Looping)
788 ALuint DataSize = min(BufferSize, pos);
790 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, DataSize);
791 SrcDataSize += DataSize;
792 BufferSize -= DataSize;
794 pos = 0;
795 break;
798 if(Looping)
800 while(BufferListIter->next)
801 BufferListIter = BufferListIter->next;
803 else
804 BufferListIter = BufferListIter->prev;
806 if(BufferListIter->buffer)
808 if((ALuint)BufferListIter->buffer->size > pos)
810 pos = BufferListIter->buffer->size - pos;
811 break;
813 pos -= BufferListIter->buffer->size;
818 while(BufferListIter && BufferSize > 0)
820 const ALbuffer *ALBuffer;
821 if((ALBuffer=BufferListIter->buffer) != NULL)
823 const ALubyte *Data = ALBuffer->data;
824 ALuint DataSize = ALBuffer->size;
826 /* Skip the data already played */
827 if(DataSize <= pos)
828 pos -= DataSize;
829 else
831 Data += pos;
832 DataSize -= pos;
833 pos -= pos;
835 DataSize = min(BufferSize, DataSize);
836 memcpy(&SrcData[SrcDataSize], Data, DataSize);
837 SrcDataSize += DataSize;
838 BufferSize -= DataSize;
841 BufferListIter = BufferListIter->next;
842 if(!BufferListIter && Looping)
843 BufferListIter = Source->queue;
844 else if(!BufferListIter)
846 memset(&SrcData[SrcDataSize], (Bytes==1)?0x80:0, BufferSize);
847 SrcDataSize += BufferSize;
848 BufferSize -= BufferSize;
853 /* Figure out how many samples we can mix. */
854 DataSize64 = SrcDataSize / FrameSize;
855 DataSize64 -= BufferPadding+BufferPrePadding;
856 DataSize64 <<= FRACTIONBITS;
857 DataSize64 -= increment;
859 BufferSize = (ALuint)((DataSize64-DataPosFrac+(increment-1)) / increment);
860 BufferSize = min(BufferSize, (SamplesToDo-OutPos));
861 if(BufferSize == 0)
863 AL_PRINT("No samples to mix! Pitch too high (%u, %g)?\n",
864 increment, increment/(double)FRACTIONONE);
865 State = AL_STOPPED;
866 BufferListItem = Source->queue;
867 BuffersPlayed = Source->BuffersInQueue;
868 DataPosInt = 0;
869 DataPosFrac = 0;
870 break;
873 SrcData += BufferPrePadding*FrameSize;
874 switch(Resampler)
876 case POINT_RESAMPLER:
877 if(Bytes == 4)
878 Mix_ALfloat_point32(Source, Device, Channels,
879 SrcData, &DataPosInt, &DataPosFrac,
880 OutPos, SamplesToDo, BufferSize);
881 else if(Bytes == 2)
882 Mix_ALshort_point16(Source, Device, Channels,
883 SrcData, &DataPosInt, &DataPosFrac,
884 OutPos, SamplesToDo, BufferSize);
885 else if(Bytes == 1)
886 Mix_ALubyte_point8(Source, Device, Channels,
887 SrcData, &DataPosInt, &DataPosFrac,
888 OutPos, SamplesToDo, BufferSize);
889 break;
890 case LINEAR_RESAMPLER:
891 if(Bytes == 4)
892 Mix_ALfloat_lerp32(Source, Device, Channels,
893 SrcData, &DataPosInt, &DataPosFrac,
894 OutPos, SamplesToDo, BufferSize);
895 else if(Bytes == 2)
896 Mix_ALshort_lerp16(Source, Device, Channels,
897 SrcData, &DataPosInt, &DataPosFrac,
898 OutPos, SamplesToDo, BufferSize);
899 else if(Bytes == 1)
900 Mix_ALubyte_lerp8(Source, Device, Channels,
901 SrcData, &DataPosInt, &DataPosFrac,
902 OutPos, SamplesToDo, BufferSize);
903 break;
904 case CUBIC_RESAMPLER:
905 if(Bytes == 4)
906 Mix_ALfloat_cubic32(Source, Device, Channels,
907 SrcData, &DataPosInt, &DataPosFrac,
908 OutPos, SamplesToDo, BufferSize);
909 else if(Bytes == 2)
910 Mix_ALshort_cubic16(Source, Device, Channels,
911 SrcData, &DataPosInt, &DataPosFrac,
912 OutPos, SamplesToDo, BufferSize);
913 else if(Bytes == 1)
914 Mix_ALubyte_cubic8(Source, Device, Channels,
915 SrcData, &DataPosInt, &DataPosFrac,
916 OutPos, SamplesToDo, BufferSize);
917 break;
918 case RESAMPLER_MIN:
919 case RESAMPLER_MAX:
920 break;
922 OutPos += BufferSize;
924 /* Handle looping sources */
925 while(1)
927 const ALbuffer *ALBuffer;
928 ALuint DataSize = 0;
929 ALuint LoopStart = 0;
930 ALuint LoopEnd = 0;
932 if((ALBuffer=BufferListItem->buffer) != NULL)
934 DataSize = ALBuffer->size / FrameSize;
935 if(DataSize > DataPosInt)
936 break;
937 LoopStart = ALBuffer->LoopStart;
938 LoopEnd = ALBuffer->LoopEnd;
941 if(BufferListItem->next)
943 BufferListItem = BufferListItem->next;
944 BuffersPlayed++;
946 else if(Looping)
948 BufferListItem = Source->queue;
949 BuffersPlayed = 0;
950 if(Source->lSourceType == AL_STATIC)
952 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
953 break;
956 else
958 State = AL_STOPPED;
959 BufferListItem = Source->queue;
960 BuffersPlayed = Source->BuffersInQueue;
961 DataPosInt = 0;
962 DataPosFrac = 0;
963 break;
966 DataPosInt -= DataSize;
968 } while(State == AL_PLAYING && OutPos < SamplesToDo);
970 /* Update source info */
971 Source->state = State;
972 Source->BuffersPlayed = BuffersPlayed;
973 Source->position = DataPosInt;
974 Source->position_fraction = DataPosFrac;
975 Source->Buffer = BufferListItem->buffer;