2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
40 static __inline 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) \
71 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
72 ALfloat *ClickRemoval, *PendingClicks; \
74 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
91 frac = *DataPosFrac; \
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]; \
124 pos += frac>>FRACTIONBITS; \
125 frac &= FRACTIONMASK; \
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++) \
146 ALfloat *WetBuffer; \
147 ALfloat *WetClickRemoval; \
148 ALfloat *WetPendingClicks; \
151 if(!Source->Send[out].Slot || \
152 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
162 frac = *DataPosFrac; \
163 OutPos -= BufferSize; \
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; \
182 pos += frac>>FRACTIONBITS; \
183 frac &= FRACTIONMASK; \
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
)
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 \
224 const ALfloat scaler = 1.0f/Channels; \
225 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
226 ALfloat *ClickRemoval, *PendingClicks; \
228 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
245 frac = *DataPosFrac; \
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]]; \
272 pos += frac>>FRACTIONBITS; \
273 frac &= FRACTIONMASK; \
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++) \
292 ALfloat *WetBuffer; \
293 ALfloat *WetClickRemoval; \
294 ALfloat *WetPendingClicks; \
297 if(!Source->Send[out].Slot || \
298 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
308 frac = *DataPosFrac; \
309 OutPos -= BufferSize; \
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; \
332 pos += frac>>FRACTIONBITS; \
333 frac &= FRACTIONMASK; \
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
)
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; \
376 ALfloat DrySend[OUTPUTCHANNELS]; \
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]; \
393 frac = *DataPosFrac; \
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]]; \
416 pos += frac>>FRACTIONBITS; \
417 frac &= FRACTIONMASK; \
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++) \
434 ALfloat *WetBuffer; \
435 ALfloat *WetClickRemoval; \
436 ALfloat *WetPendingClicks; \
439 if(!Source->Send[out].Slot || \
440 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
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; \
450 frac = *DataPosFrac; \
451 OutPos -= BufferSize; \
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; \
474 pos += frac>>FRACTIONBITS; \
475 frac &= FRACTIONMASK; \
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 RearChans
[] = { BACK_LEFT
, BACK_RIGHT
};
509 DECL_TEMPLATE(ALfloat
, RearChans
, point32
)
510 DECL_TEMPLATE(ALfloat
, RearChans
, lerp32
)
511 DECL_TEMPLATE(ALfloat
, RearChans
, cubic32
)
513 DECL_TEMPLATE(ALshort
, RearChans
, point16
)
514 DECL_TEMPLATE(ALshort
, RearChans
, lerp16
)
515 DECL_TEMPLATE(ALshort
, RearChans
, cubic16
)
517 DECL_TEMPLATE(ALubyte
, RearChans
, point8
)
518 DECL_TEMPLATE(ALubyte
, RearChans
, lerp8
)
519 DECL_TEMPLATE(ALubyte
, RearChans
, cubic8
)
522 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
524 BACK_LEFT
, BACK_RIGHT
};
525 DECL_TEMPLATE(ALfloat
, X51Chans
, point32
)
526 DECL_TEMPLATE(ALfloat
, X51Chans
, lerp32
)
527 DECL_TEMPLATE(ALfloat
, X51Chans
, cubic32
)
529 DECL_TEMPLATE(ALshort
, X51Chans
, point16
)
530 DECL_TEMPLATE(ALshort
, X51Chans
, lerp16
)
531 DECL_TEMPLATE(ALshort
, X51Chans
, cubic16
)
533 DECL_TEMPLATE(ALubyte
, X51Chans
, point8
)
534 DECL_TEMPLATE(ALubyte
, X51Chans
, lerp8
)
535 DECL_TEMPLATE(ALubyte
, X51Chans
, cubic8
)
538 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
541 SIDE_LEFT
, SIDE_RIGHT
};
542 DECL_TEMPLATE(ALfloat
, X61Chans
, point32
)
543 DECL_TEMPLATE(ALfloat
, X61Chans
, lerp32
)
544 DECL_TEMPLATE(ALfloat
, X61Chans
, cubic32
)
546 DECL_TEMPLATE(ALshort
, X61Chans
, point16
)
547 DECL_TEMPLATE(ALshort
, X61Chans
, lerp16
)
548 DECL_TEMPLATE(ALshort
, X61Chans
, cubic16
)
550 DECL_TEMPLATE(ALubyte
, X61Chans
, point8
)
551 DECL_TEMPLATE(ALubyte
, X61Chans
, lerp8
)
552 DECL_TEMPLATE(ALubyte
, X61Chans
, cubic8
)
555 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
557 BACK_LEFT
, BACK_RIGHT
,
558 SIDE_LEFT
, SIDE_RIGHT
};
559 DECL_TEMPLATE(ALfloat
, X71Chans
, point32
)
560 DECL_TEMPLATE(ALfloat
, X71Chans
, lerp32
)
561 DECL_TEMPLATE(ALfloat
, X71Chans
, cubic32
)
563 DECL_TEMPLATE(ALshort
, X71Chans
, point16
)
564 DECL_TEMPLATE(ALshort
, X71Chans
, lerp16
)
565 DECL_TEMPLATE(ALshort
, X71Chans
, cubic16
)
567 DECL_TEMPLATE(ALubyte
, X71Chans
, point8
)
568 DECL_TEMPLATE(ALubyte
, X71Chans
, lerp8
)
569 DECL_TEMPLATE(ALubyte
, X71Chans
, cubic8
)
574 #define DECL_TEMPLATE(T, sampler) \
575 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
576 enum FmtChannels FmtChannels, \
577 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
578 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
580 switch(FmtChannels) \
583 Mix_##T##_Mono_##sampler(Source, Device, \
584 Data, DataPosInt, DataPosFrac, \
585 OutPos, SamplesToDo, BufferSize); \
588 Mix_##T##_Stereo_##sampler(Source, Device, \
589 Data, DataPosInt, DataPosFrac, \
590 OutPos, SamplesToDo, BufferSize); \
593 Mix_##T##_QuadChans_##sampler(Source, Device, \
594 Data, DataPosInt, DataPosFrac, \
595 OutPos, SamplesToDo, BufferSize); \
598 Mix_##T##_RearChans_##sampler(Source, Device, \
599 Data, DataPosInt, DataPosFrac, \
600 OutPos, SamplesToDo, BufferSize); \
603 Mix_##T##_X51Chans_##sampler(Source, Device, \
604 Data, DataPosInt, DataPosFrac, \
605 OutPos, SamplesToDo, BufferSize); \
608 Mix_##T##_X61Chans_##sampler(Source, Device, \
609 Data, DataPosInt, DataPosFrac, \
610 OutPos, SamplesToDo, BufferSize); \
613 Mix_##T##_X71Chans_##sampler(Source, Device, \
614 Data, DataPosInt, DataPosFrac, \
615 OutPos, SamplesToDo, BufferSize); \
620 DECL_TEMPLATE(ALfloat
, point32
)
621 DECL_TEMPLATE(ALfloat
, lerp32
)
622 DECL_TEMPLATE(ALfloat
, cubic32
)
624 DECL_TEMPLATE(ALshort
, point16
)
625 DECL_TEMPLATE(ALshort
, lerp16
)
626 DECL_TEMPLATE(ALshort
, cubic16
)
628 DECL_TEMPLATE(ALubyte
, point8
)
629 DECL_TEMPLATE(ALubyte
, lerp8
)
630 DECL_TEMPLATE(ALubyte
, cubic8
)
635 #define DECL_TEMPLATE(sampler) \
636 static void Mix_##sampler(ALsource *Source, ALCdevice *Device, \
637 enum FmtChannels FmtChannels, enum FmtType FmtType, \
638 const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac, \
639 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
644 Mix_ALubyte_##sampler##8(Source, Device, FmtChannels, \
645 Data, DataPosInt, DataPosFrac, \
646 OutPos, SamplesToDo, BufferSize); \
650 Mix_ALshort_##sampler##16(Source, Device, FmtChannels, \
651 Data, DataPosInt, DataPosFrac, \
652 OutPos, SamplesToDo, BufferSize); \
656 Mix_ALfloat_##sampler##32(Source, Device, FmtChannels, \
657 Data, DataPosInt, DataPosFrac, \
658 OutPos, SamplesToDo, BufferSize); \
670 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
672 ALbufferlistitem
*BufferListItem
;
673 ALuint DataPosInt
, DataPosFrac
;
674 enum FmtChannels FmtChannels
;
675 enum FmtType FmtType
;
676 ALuint BuffersPlayed
;
679 resampler_t Resampler
;
686 /* Get source info */
687 State
= Source
->state
;
688 BuffersPlayed
= Source
->BuffersPlayed
;
689 DataPosInt
= Source
->position
;
690 DataPosFrac
= Source
->position_fraction
;
691 Looping
= Source
->bLooping
;
692 increment
= Source
->Params
.Step
;
693 Resampler
= (increment
== FRACTIONONE
) ? POINT_RESAMPLER
:
696 /* Get buffer info */
698 FmtChannels
= FmtMono
;
700 BufferListItem
= Source
->queue
;
701 for(i
= 0;i
< Source
->BuffersInQueue
;i
++)
703 const ALbuffer
*ALBuffer
;
704 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
706 FmtChannels
= ALBuffer
->FmtChannels
;
707 FmtType
= ALBuffer
->FmtType
;
708 FrameSize
= FrameSizeFromFmt(FmtChannels
, FmtType
);
711 BufferListItem
= BufferListItem
->next
;
714 /* Get current buffer queue item */
715 BufferListItem
= Source
->queue
;
716 for(i
= 0;i
< BuffersPlayed
;i
++)
717 BufferListItem
= BufferListItem
->next
;
721 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
722 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
723 ALubyte StackData
[STACK_DATA_SIZE
];
724 ALubyte
*SrcData
= StackData
;
725 ALuint SrcDataSize
= 0;
728 /* Figure out how many buffer bytes will be needed */
729 DataSize64
= SamplesToDo
-OutPos
+1;
730 DataSize64
*= increment
;
731 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
732 DataSize64
>>= FRACTIONBITS
;
733 DataSize64
+= BufferPadding
+BufferPrePadding
;
734 DataSize64
*= FrameSize
;
736 BufferSize
= min(DataSize64
, STACK_DATA_SIZE
);
737 BufferSize
-= BufferSize
%FrameSize
;
739 if(Source
->lSourceType
== AL_STATIC
)
741 const ALbuffer
*ALBuffer
= Source
->Buffer
;
742 const ALubyte
*Data
= ALBuffer
->data
;
746 /* If current pos is beyond the loop range, do not loop */
747 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
751 if(DataPosInt
>= BufferPrePadding
)
752 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
755 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
756 DataSize
= min(BufferSize
, DataSize
);
758 memset(&SrcData
[SrcDataSize
], (FmtType
==FmtUByte
)?0x80:0, DataSize
);
759 SrcDataSize
+= DataSize
;
760 BufferSize
-= DataSize
;
765 /* Copy what's left to play in the source buffer, and clear the
766 * rest of the temp buffer */
767 DataSize
= ALBuffer
->size
- pos
;
768 DataSize
= min(BufferSize
, DataSize
);
770 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
771 SrcDataSize
+= DataSize
;
772 BufferSize
-= DataSize
;
774 memset(&SrcData
[SrcDataSize
], (FmtType
==FmtUByte
)?0x80:0, BufferSize
);
775 SrcDataSize
+= BufferSize
;
776 BufferSize
-= BufferSize
;
780 ALuint LoopStart
= ALBuffer
->LoopStart
;
781 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
783 if(DataPosInt
>= LoopStart
)
785 pos
= DataPosInt
-LoopStart
;
786 while(pos
< BufferPrePadding
)
787 pos
+= LoopEnd
-LoopStart
;
788 pos
-= BufferPrePadding
;
792 else if(DataPosInt
>= BufferPrePadding
)
793 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
796 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
797 DataSize
= min(BufferSize
, DataSize
);
799 memset(&SrcData
[SrcDataSize
], (FmtType
==FmtUByte
)?0x80:0, DataSize
);
800 SrcDataSize
+= DataSize
;
801 BufferSize
-= DataSize
;
806 /* Copy what's left of this loop iteration, then copy repeats
807 * of the loop section */
808 DataSize
= LoopEnd
*FrameSize
- pos
;
809 DataSize
= min(BufferSize
, DataSize
);
811 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
812 SrcDataSize
+= DataSize
;
813 BufferSize
-= DataSize
;
815 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
816 while(BufferSize
> 0)
818 DataSize
= min(BufferSize
, DataSize
);
820 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
821 SrcDataSize
+= DataSize
;
822 BufferSize
-= DataSize
;
828 /* Crawl the buffer queue to fill in the temp buffer */
829 ALbufferlistitem
*BufferListIter
= BufferListItem
;
832 if(DataPosInt
>= BufferPrePadding
)
833 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
836 pos
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
839 if(!BufferListIter
->prev
&& !Looping
)
841 ALuint DataSize
= min(BufferSize
, pos
);
843 memset(&SrcData
[SrcDataSize
], (FmtType
==FmtUByte
)?0x80:0, DataSize
);
844 SrcDataSize
+= DataSize
;
845 BufferSize
-= DataSize
;
853 while(BufferListIter
->next
)
854 BufferListIter
= BufferListIter
->next
;
857 BufferListIter
= BufferListIter
->prev
;
859 if(BufferListIter
->buffer
)
861 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
863 pos
= BufferListIter
->buffer
->size
- pos
;
866 pos
-= BufferListIter
->buffer
->size
;
871 while(BufferListIter
&& BufferSize
> 0)
873 const ALbuffer
*ALBuffer
;
874 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
876 const ALubyte
*Data
= ALBuffer
->data
;
877 ALuint DataSize
= ALBuffer
->size
;
879 /* Skip the data already played */
888 DataSize
= min(BufferSize
, DataSize
);
889 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
890 SrcDataSize
+= DataSize
;
891 BufferSize
-= DataSize
;
894 BufferListIter
= BufferListIter
->next
;
895 if(!BufferListIter
&& Looping
)
896 BufferListIter
= Source
->queue
;
897 else if(!BufferListIter
)
899 memset(&SrcData
[SrcDataSize
], (FmtType
==FmtUByte
)?0x80:0, BufferSize
);
900 SrcDataSize
+= BufferSize
;
901 BufferSize
-= BufferSize
;
906 /* Figure out how many samples we can mix. */
907 DataSize64
= SrcDataSize
/ FrameSize
;
908 DataSize64
-= BufferPadding
+BufferPrePadding
;
909 DataSize64
<<= FRACTIONBITS
;
910 DataSize64
-= increment
;
911 DataSize64
-= DataPosFrac
;
913 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
914 BufferSize
= min(BufferSize
, (SamplesToDo
-OutPos
));
916 SrcData
+= BufferPrePadding
*FrameSize
;
919 case POINT_RESAMPLER
:
920 Mix_point(Source
, Device
, FmtChannels
, FmtType
,
921 SrcData
, &DataPosInt
, &DataPosFrac
,
922 OutPos
, SamplesToDo
, BufferSize
);
924 case LINEAR_RESAMPLER
:
925 Mix_lerp(Source
, Device
, FmtChannels
, FmtType
,
926 SrcData
, &DataPosInt
, &DataPosFrac
,
927 OutPos
, SamplesToDo
, BufferSize
);
929 case CUBIC_RESAMPLER
:
930 Mix_cubic(Source
, Device
, FmtChannels
, FmtType
,
931 SrcData
, &DataPosInt
, &DataPosFrac
,
932 OutPos
, SamplesToDo
, BufferSize
);
938 OutPos
+= BufferSize
;
940 /* Handle looping sources */
943 const ALbuffer
*ALBuffer
;
945 ALuint LoopStart
= 0;
948 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
950 DataSize
= ALBuffer
->size
/ FrameSize
;
951 if(DataSize
> DataPosInt
)
953 LoopStart
= ALBuffer
->LoopStart
;
954 LoopEnd
= ALBuffer
->LoopEnd
;
957 if(BufferListItem
->next
)
959 BufferListItem
= BufferListItem
->next
;
964 BufferListItem
= Source
->queue
;
966 if(Source
->lSourceType
== AL_STATIC
)
968 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
975 BufferListItem
= Source
->queue
;
976 BuffersPlayed
= Source
->BuffersInQueue
;
982 DataPosInt
-= DataSize
;
984 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
986 /* Update source info */
987 Source
->state
= State
;
988 Source
->BuffersPlayed
= BuffersPlayed
;
989 Source
->position
= DataPosInt
;
990 Source
->position_fraction
= DataPosFrac
;
991 Source
->Buffer
= BufferListItem
->buffer
;