view Alc/mixer.c @ 19:22ac5a0367cd

finally, a first pass at ear.org
author Robert McIntyre <rlm@mit.edu>
date Thu, 03 Nov 2011 14:54:45 -0700
parents f9476ff7637e
children
line wrap: on
line source
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.
8 *
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.
13 *
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
19 */
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 ALbyte *vals, ALint step, ALint frac)
57 { return vals[0] * (1.0/127.0); (void)step; (void)frac; }
58 static __inline ALdouble lerp8(const ALbyte *vals, ALint step, ALint frac)
59 { return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)) * (1.0/127.0); }
60 static __inline ALdouble cubic8(const ALbyte *vals, ALint step, ALint frac)
61 { return cubic(vals[-step], vals[0], vals[step], vals[step+step],
62 frac * (1.0/FRACTIONONE)) * (1.0/127.0); }
64 #ifdef __GNUC__
65 #define LIKELY(x) __builtin_expect(!!(x), 1)
66 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
67 #else
68 #define LIKELY(x) (x)
69 #define UNLIKELY(x) (x)
70 #endif
72 #if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_H)
73 #include <arm_neon.h>
75 static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
76 ALfloat (*RESTRICT Coeffs)[2],
77 ALfloat left, ALfloat right)
78 {
79 ALuint c;
80 float32x4_t leftright4;
81 {
82 float32x2_t leftright2 = vdup_n_f32(0.0);
83 leftright2 = vset_lane_f32(left, leftright2, 0);
84 leftright2 = vset_lane_f32(right, leftright2, 1);
85 leftright4 = vcombine_f32(leftright2, leftright2);
86 }
87 for(c = 0;c < HRIR_LENGTH;c += 2)
88 {
89 const ALuint o0 = (Offset+c)&HRIR_MASK;
90 const ALuint o1 = (o0+1)&HRIR_MASK;
91 float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
92 vld1_f32((float32_t*)&Values[o1][0]));
93 float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
95 vals = vmlaq_f32(vals, coefs, leftright4);
97 vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
98 vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
99 }
100 }
102 #else
104 static __inline void ApplyCoeffs(ALuint Offset, ALfloat (*RESTRICT Values)[2],
105 ALfloat (*RESTRICT Coeffs)[2],
106 ALfloat left, ALfloat right)
107 {
108 ALuint c;
109 for(c = 0;c < HRIR_LENGTH;c++)
110 {
111 const ALuint off = (Offset+c)&HRIR_MASK;
112 Values[off][0] += Coeffs[c][0] * left;
113 Values[off][1] += Coeffs[c][1] * right;
114 }
115 }
117 #endif
119 #define DECL_TEMPLATE(T, sampler) \
120 static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
121 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
122 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
123 { \
124 const ALuint NumChannels = Source->NumChannels; \
125 const T *RESTRICT data = srcdata; \
126 const ALint *RESTRICT DelayStep = Source->Params.HrtfDelayStep; \
127 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
128 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
129 ALfloat (*RESTRICT CoeffStep)[2] = Source->Params.HrtfCoeffStep; \
130 ALuint pos, frac; \
131 FILTER *DryFilter; \
132 ALuint BufferIdx; \
133 ALuint increment; \
134 ALuint i, out, c; \
135 ALfloat value; \
136 \
137 increment = Source->Params.Step; \
138 \
139 DryBuffer = Device->DryBuffer; \
140 ClickRemoval = Device->ClickRemoval; \
141 PendingClicks = Device->PendingClicks; \
142 DryFilter = &Source->Params.iirFilter; \
143 \
144 pos = 0; \
145 frac = *DataPosFrac; \
146 \
147 for(i = 0;i < NumChannels;i++) \
148 { \
149 ALfloat (*RESTRICT TargetCoeffs)[2] = Source->Params.HrtfCoeffs[i]; \
150 ALuint *RESTRICT TargetDelay = Source->Params.HrtfDelay[i]; \
151 ALfloat *RESTRICT History = Source->HrtfHistory[i]; \
152 ALfloat (*RESTRICT Values)[2] = Source->HrtfValues[i]; \
153 ALint Counter = maxu(Source->HrtfCounter, OutPos) - OutPos; \
154 ALuint Offset = Source->HrtfOffset + OutPos; \
155 ALfloat Coeffs[HRIR_LENGTH][2]; \
156 ALuint Delay[2]; \
157 ALfloat left, right; \
158 \
159 pos = 0; \
160 frac = *DataPosFrac; \
161 \
162 for(c = 0;c < HRIR_LENGTH;c++) \
163 { \
164 Coeffs[c][0] = TargetCoeffs[c][0] - (CoeffStep[c][0]*Counter); \
165 Coeffs[c][1] = TargetCoeffs[c][1] - (CoeffStep[c][1]*Counter); \
166 } \
167 \
168 Delay[0] = TargetDelay[0] - (DelayStep[0]*Counter) + 32768; \
169 Delay[1] = TargetDelay[1] - (DelayStep[1]*Counter) + 32768; \
170 \
171 if(LIKELY(OutPos == 0)) \
172 { \
173 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
174 value = lpFilter2PC(DryFilter, i, value); \
175 \
176 History[Offset&SRC_HISTORY_MASK] = value; \
177 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
178 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
179 \
180 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \
181 Coeffs[0][0] * left; \
182 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \
183 Coeffs[0][1] * right; \
184 } \
185 for(BufferIdx = 0;BufferIdx < BufferSize && Counter > 0;BufferIdx++) \
186 { \
187 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
188 value = lpFilter2P(DryFilter, i, value); \
189 \
190 History[Offset&SRC_HISTORY_MASK] = value; \
191 left = History[(Offset-(Delay[0]>>16))&SRC_HISTORY_MASK]; \
192 right = History[(Offset-(Delay[1]>>16))&SRC_HISTORY_MASK]; \
193 \
194 Delay[0] += DelayStep[0]; \
195 Delay[1] += DelayStep[1]; \
196 \
197 Values[Offset&HRIR_MASK][0] = 0.0f; \
198 Values[Offset&HRIR_MASK][1] = 0.0f; \
199 Offset++; \
200 \
201 for(c = 0;c < HRIR_LENGTH;c++) \
202 { \
203 const ALuint off = (Offset+c)&HRIR_MASK; \
204 Values[off][0] += Coeffs[c][0] * left; \
205 Values[off][1] += Coeffs[c][1] * right; \
206 Coeffs[c][0] += CoeffStep[c][0]; \
207 Coeffs[c][1] += CoeffStep[c][1]; \
208 } \
209 \
210 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
211 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
212 \
213 frac += increment; \
214 pos += frac>>FRACTIONBITS; \
215 frac &= FRACTIONMASK; \
216 OutPos++; \
217 Counter--; \
218 } \
219 \
220 Delay[0] >>= 16; \
221 Delay[1] >>= 16; \
222 for(;BufferIdx < BufferSize;BufferIdx++) \
223 { \
224 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
225 value = lpFilter2P(DryFilter, i, value); \
226 \
227 History[Offset&SRC_HISTORY_MASK] = value; \
228 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
229 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
230 \
231 Values[Offset&HRIR_MASK][0] = 0.0f; \
232 Values[Offset&HRIR_MASK][1] = 0.0f; \
233 Offset++; \
234 \
235 ApplyCoeffs(Offset, Values, Coeffs, left, right); \
236 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
237 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
238 \
239 frac += increment; \
240 pos += frac>>FRACTIONBITS; \
241 frac &= FRACTIONMASK; \
242 OutPos++; \
243 } \
244 if(LIKELY(OutPos == SamplesToDo)) \
245 { \
246 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
247 value = lpFilter2PC(DryFilter, i, value); \
248 \
249 History[Offset&SRC_HISTORY_MASK] = value; \
250 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
251 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
252 \
253 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \
254 Coeffs[0][0] * left; \
255 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \
256 Coeffs[0][1] * right; \
257 } \
258 OutPos -= BufferSize; \
259 } \
260 \
261 for(out = 0;out < Device->NumAuxSends;out++) \
262 { \
263 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
264 ALfloat WetSend; \
265 ALfloat *RESTRICT WetBuffer; \
266 ALfloat *RESTRICT WetClickRemoval; \
267 ALfloat *RESTRICT WetPendingClicks; \
268 FILTER *WetFilter; \
269 \
270 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
271 continue; \
272 \
273 WetBuffer = Slot->WetBuffer; \
274 WetClickRemoval = Slot->ClickRemoval; \
275 WetPendingClicks = Slot->PendingClicks; \
276 WetFilter = &Source->Params.Send[out].iirFilter; \
277 WetSend = Source->Params.Send[out].WetGain; \
278 \
279 for(i = 0;i < NumChannels;i++) \
280 { \
281 pos = 0; \
282 frac = *DataPosFrac; \
283 \
284 if(LIKELY(OutPos == 0)) \
285 { \
286 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
287 value = lpFilter1PC(WetFilter, i, value); \
288 \
289 WetClickRemoval[0] -= value * WetSend; \
290 } \
291 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
292 { \
293 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
294 value = lpFilter1P(WetFilter, i, value); \
295 \
296 WetBuffer[OutPos] += value * WetSend; \
297 \
298 frac += increment; \
299 pos += frac>>FRACTIONBITS; \
300 frac &= FRACTIONMASK; \
301 OutPos++; \
302 } \
303 if(LIKELY(OutPos == SamplesToDo)) \
304 { \
305 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
306 value = lpFilter1PC(WetFilter, i, value); \
307 \
308 WetPendingClicks[0] += value * WetSend; \
309 } \
310 OutPos -= BufferSize; \
311 } \
312 } \
313 *DataPosInt += pos; \
314 *DataPosFrac = frac; \
315 }
317 DECL_TEMPLATE(ALfloat, point32)
318 DECL_TEMPLATE(ALfloat, lerp32)
319 DECL_TEMPLATE(ALfloat, cubic32)
321 DECL_TEMPLATE(ALshort, point16)
322 DECL_TEMPLATE(ALshort, lerp16)
323 DECL_TEMPLATE(ALshort, cubic16)
325 DECL_TEMPLATE(ALbyte, point8)
326 DECL_TEMPLATE(ALbyte, lerp8)
327 DECL_TEMPLATE(ALbyte, cubic8)
329 #undef DECL_TEMPLATE
332 #define DECL_TEMPLATE(T, sampler) \
333 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
334 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
335 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
336 { \
337 const ALuint NumChannels = Source->NumChannels; \
338 const T *RESTRICT data = srcdata; \
339 ALfloat (*DryBuffer)[MAXCHANNELS]; \
340 ALfloat *ClickRemoval, *PendingClicks; \
341 ALuint pos, frac; \
342 ALfloat DrySend[MAXCHANNELS][MAXCHANNELS]; \
343 FILTER *DryFilter; \
344 ALuint BufferIdx; \
345 ALuint increment; \
346 ALuint i, out, c; \
347 ALfloat value; \
348 \
349 increment = Source->Params.Step; \
350 \
351 DryBuffer = Device->DryBuffer; \
352 ClickRemoval = Device->ClickRemoval; \
353 PendingClicks = Device->PendingClicks; \
354 DryFilter = &Source->Params.iirFilter; \
355 for(i = 0;i < NumChannels;i++) \
356 { \
357 for(c = 0;c < MAXCHANNELS;c++) \
358 DrySend[i][c] = Source->Params.DryGains[i][c]; \
359 } \
360 \
361 pos = 0; \
362 frac = *DataPosFrac; \
363 \
364 for(i = 0;i < NumChannels;i++) \
365 { \
366 pos = 0; \
367 frac = *DataPosFrac; \
368 \
369 if(OutPos == 0) \
370 { \
371 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
372 \
373 value = lpFilter2PC(DryFilter, i, value); \
374 for(c = 0;c < MAXCHANNELS;c++) \
375 ClickRemoval[c] -= value*DrySend[i][c]; \
376 } \
377 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
378 { \
379 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
380 \
381 value = lpFilter2P(DryFilter, i, value); \
382 for(c = 0;c < MAXCHANNELS;c++) \
383 DryBuffer[OutPos][c] += value*DrySend[i][c]; \
384 \
385 frac += increment; \
386 pos += frac>>FRACTIONBITS; \
387 frac &= FRACTIONMASK; \
388 OutPos++; \
389 } \
390 if(OutPos == SamplesToDo) \
391 { \
392 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
393 \
394 value = lpFilter2PC(DryFilter, i, value); \
395 for(c = 0;c < MAXCHANNELS;c++) \
396 PendingClicks[c] += value*DrySend[i][c]; \
397 } \
398 OutPos -= BufferSize; \
399 } \
400 \
401 for(out = 0;out < Device->NumAuxSends;out++) \
402 { \
403 ALeffectslot *Slot = Source->Params.Send[out].Slot; \
404 ALfloat WetSend; \
405 ALfloat *WetBuffer; \
406 ALfloat *WetClickRemoval; \
407 ALfloat *WetPendingClicks; \
408 FILTER *WetFilter; \
409 \
410 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
411 continue; \
412 \
413 WetBuffer = Slot->WetBuffer; \
414 WetClickRemoval = Slot->ClickRemoval; \
415 WetPendingClicks = Slot->PendingClicks; \
416 WetFilter = &Source->Params.Send[out].iirFilter; \
417 WetSend = Source->Params.Send[out].WetGain; \
418 \
419 for(i = 0;i < NumChannels;i++) \
420 { \
421 pos = 0; \
422 frac = *DataPosFrac; \
423 \
424 if(OutPos == 0) \
425 { \
426 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
427 \
428 value = lpFilter1PC(WetFilter, i, value); \
429 WetClickRemoval[0] -= value * WetSend; \
430 } \
431 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
432 { \
433 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
434 \
435 value = lpFilter1P(WetFilter, i, value); \
436 WetBuffer[OutPos] += value * WetSend; \
437 \
438 frac += increment; \
439 pos += frac>>FRACTIONBITS; \
440 frac &= FRACTIONMASK; \
441 OutPos++; \
442 } \
443 if(OutPos == SamplesToDo) \
444 { \
445 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
446 \
447 value = lpFilter1PC(WetFilter, i, value); \
448 WetPendingClicks[0] += value * WetSend; \
449 } \
450 OutPos -= BufferSize; \
451 } \
452 } \
453 *DataPosInt += pos; \
454 *DataPosFrac = frac; \
455 }
457 DECL_TEMPLATE(ALfloat, point32)
458 DECL_TEMPLATE(ALfloat, lerp32)
459 DECL_TEMPLATE(ALfloat, cubic32)
461 DECL_TEMPLATE(ALshort, point16)
462 DECL_TEMPLATE(ALshort, lerp16)
463 DECL_TEMPLATE(ALshort, cubic16)
465 DECL_TEMPLATE(ALbyte, point8)
466 DECL_TEMPLATE(ALbyte, lerp8)
467 DECL_TEMPLATE(ALbyte, cubic8)
469 #undef DECL_TEMPLATE
472 #define DECL_TEMPLATE(sampler) \
473 static MixerFunc Select_##sampler(enum FmtType FmtType) \
474 { \
475 switch(FmtType) \
476 { \
477 case FmtByte: \
478 return Mix_ALbyte_##sampler##8; \
479 case FmtShort: \
480 return Mix_ALshort_##sampler##16; \
481 case FmtFloat: \
482 return Mix_ALfloat_##sampler##32; \
483 } \
484 return NULL; \
485 }
487 DECL_TEMPLATE(point)
488 DECL_TEMPLATE(lerp)
489 DECL_TEMPLATE(cubic)
491 #undef DECL_TEMPLATE
493 MixerFunc SelectMixer(ALbuffer *Buffer, enum Resampler Resampler)
494 {
495 switch(Resampler)
496 {
497 case POINT_RESAMPLER:
498 return Select_point(Buffer->FmtType);
499 case LINEAR_RESAMPLER:
500 return Select_lerp(Buffer->FmtType);
501 case CUBIC_RESAMPLER:
502 return Select_cubic(Buffer->FmtType);
503 case RESAMPLER_MIN:
504 case RESAMPLER_MAX:
505 break;
506 }
507 return NULL;
508 }
510 #define DECL_TEMPLATE(sampler) \
511 static MixerFunc Select_Hrtf_##sampler(enum FmtType FmtType) \
512 { \
513 switch(FmtType) \
514 { \
515 case FmtByte: \
516 return Mix_Hrtf_ALbyte_##sampler##8; \
517 case FmtShort: \
518 return Mix_Hrtf_ALshort_##sampler##16; \
519 case FmtFloat: \
520 return Mix_Hrtf_ALfloat_##sampler##32; \
521 } \
522 return NULL; \
523 }
525 DECL_TEMPLATE(point)
526 DECL_TEMPLATE(lerp)
527 DECL_TEMPLATE(cubic)
529 #undef DECL_TEMPLATE
531 MixerFunc SelectHrtfMixer(ALbuffer *Buffer, enum Resampler Resampler)
532 {
533 switch(Resampler)
534 {
535 case POINT_RESAMPLER:
536 return Select_Hrtf_point(Buffer->FmtType);
537 case LINEAR_RESAMPLER:
538 return Select_Hrtf_lerp(Buffer->FmtType);
539 case CUBIC_RESAMPLER:
540 return Select_Hrtf_cubic(Buffer->FmtType);
541 case RESAMPLER_MIN:
542 case RESAMPLER_MAX:
543 break;
544 }
545 return NULL;
546 }
549 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
550 {
551 ALbufferlistitem *BufferListItem;
552 ALuint DataPosInt, DataPosFrac;
553 ALuint BuffersPlayed;
554 ALboolean Looping;
555 ALuint increment;
556 enum Resampler Resampler;
557 ALenum State;
558 ALuint OutPos;
559 ALuint FrameSize;
560 ALint64 DataSize64;
561 ALuint i;
563 /* Get source info */
564 State = Source->state;
565 BuffersPlayed = Source->BuffersPlayed;
566 DataPosInt = Source->position;
567 DataPosFrac = Source->position_fraction;
568 Looping = Source->bLooping;
569 increment = Source->Params.Step;
570 Resampler = Source->Resampler;
571 FrameSize = Source->NumChannels * Source->SampleSize;
573 /* Get current buffer queue item */
574 BufferListItem = Source->queue;
575 for(i = 0;i < BuffersPlayed;i++)
576 BufferListItem = BufferListItem->next;
578 OutPos = 0;
579 do {
580 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
581 const ALuint BufferPadding = ResamplerPadding[Resampler];
582 ALubyte StackData[STACK_DATA_SIZE];
583 ALubyte *SrcData = StackData;
584 ALuint SrcDataSize = 0;
585 ALuint BufferSize;
587 /* Figure out how many buffer bytes will be needed */
588 DataSize64 = SamplesToDo-OutPos+1;
589 DataSize64 *= increment;
590 DataSize64 += DataPosFrac+FRACTIONMASK;
591 DataSize64 >>= FRACTIONBITS;
592 DataSize64 += BufferPadding+BufferPrePadding;
593 DataSize64 *= FrameSize;
595 BufferSize = ((DataSize64 > STACK_DATA_SIZE) ? STACK_DATA_SIZE : DataSize64);
596 BufferSize -= BufferSize%FrameSize;
598 if(Source->lSourceType == AL_STATIC)
599 {
600 const ALbuffer *ALBuffer = Source->Buffer;
601 const ALubyte *Data = ALBuffer->data;
602 ALuint DataSize;
603 ALuint pos;
605 /* If current pos is beyond the loop range, do not loop */
606 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
607 {
608 Looping = AL_FALSE;
610 if(DataPosInt >= BufferPrePadding)
611 pos = (DataPosInt-BufferPrePadding)*FrameSize;
612 else
613 {
614 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
615 DataSize = minu(BufferSize, DataSize);
617 memset(&SrcData[SrcDataSize], 0, DataSize);
618 SrcDataSize += DataSize;
619 BufferSize -= DataSize;
621 pos = 0;
622 }
624 /* Copy what's left to play in the source buffer, and clear the
625 * rest of the temp buffer */
626 DataSize = ALBuffer->size - pos;
627 DataSize = minu(BufferSize, DataSize);
629 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
630 SrcDataSize += DataSize;
631 BufferSize -= DataSize;
633 memset(&SrcData[SrcDataSize], 0, BufferSize);
634 SrcDataSize += BufferSize;
635 BufferSize -= BufferSize;
636 }
637 else
638 {
639 ALuint LoopStart = ALBuffer->LoopStart;
640 ALuint LoopEnd = ALBuffer->LoopEnd;
642 if(DataPosInt >= LoopStart)
643 {
644 pos = DataPosInt-LoopStart;
645 while(pos < BufferPrePadding)
646 pos += LoopEnd-LoopStart;
647 pos -= BufferPrePadding;
648 pos += LoopStart;
649 pos *= FrameSize;
650 }
651 else if(DataPosInt >= BufferPrePadding)
652 pos = (DataPosInt-BufferPrePadding)*FrameSize;
653 else
654 {
655 DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
656 DataSize = minu(BufferSize, DataSize);
658 memset(&SrcData[SrcDataSize], 0, DataSize);
659 SrcDataSize += DataSize;
660 BufferSize -= DataSize;
662 pos = 0;
663 }
665 /* Copy what's left of this loop iteration, then copy repeats
666 * of the loop section */
667 DataSize = LoopEnd*FrameSize - pos;
668 DataSize = minu(BufferSize, DataSize);
670 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
671 SrcDataSize += DataSize;
672 BufferSize -= DataSize;
674 DataSize = (LoopEnd-LoopStart) * FrameSize;
675 while(BufferSize > 0)
676 {
677 DataSize = minu(BufferSize, DataSize);
679 memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
680 SrcDataSize += DataSize;
681 BufferSize -= DataSize;
682 }
683 }
684 }
685 else
686 {
687 /* Crawl the buffer queue to fill in the temp buffer */
688 ALbufferlistitem *BufferListIter = BufferListItem;
689 ALuint pos;
691 if(DataPosInt >= BufferPrePadding)
692 pos = (DataPosInt-BufferPrePadding)*FrameSize;
693 else
694 {
695 pos = (BufferPrePadding-DataPosInt)*FrameSize;
696 while(pos > 0)
697 {
698 if(!BufferListIter->prev && !Looping)
699 {
700 ALuint DataSize = minu(BufferSize, pos);
702 memset(&SrcData[SrcDataSize], 0, DataSize);
703 SrcDataSize += DataSize;
704 BufferSize -= DataSize;
706 pos = 0;
707 break;
708 }
710 if(BufferListIter->prev)
711 BufferListIter = BufferListIter->prev;
712 else
713 {
714 while(BufferListIter->next)
715 BufferListIter = BufferListIter->next;
716 }
718 if(BufferListIter->buffer)
719 {
720 if((ALuint)BufferListIter->buffer->size > pos)
721 {
722 pos = BufferListIter->buffer->size - pos;
723 break;
724 }
725 pos -= BufferListIter->buffer->size;
726 }
727 }
728 }
730 while(BufferListIter && BufferSize > 0)
731 {
732 const ALbuffer *ALBuffer;
733 if((ALBuffer=BufferListIter->buffer) != NULL)
734 {
735 const ALubyte *Data = ALBuffer->data;
736 ALuint DataSize = ALBuffer->size;
738 /* Skip the data already played */
739 if(DataSize <= pos)
740 pos -= DataSize;
741 else
742 {
743 Data += pos;
744 DataSize -= pos;
745 pos -= pos;
747 DataSize = minu(BufferSize, DataSize);
748 memcpy(&SrcData[SrcDataSize], Data, DataSize);
749 SrcDataSize += DataSize;
750 BufferSize -= DataSize;
751 }
752 }
753 BufferListIter = BufferListIter->next;
754 if(!BufferListIter && Looping)
755 BufferListIter = Source->queue;
756 else if(!BufferListIter)
757 {
758 memset(&SrcData[SrcDataSize], 0, BufferSize);
759 SrcDataSize += BufferSize;
760 BufferSize -= BufferSize;
761 }
762 }
763 }
765 /* Figure out how many samples we can mix. */
766 DataSize64 = SrcDataSize / FrameSize;
767 DataSize64 -= BufferPadding+BufferPrePadding;
768 DataSize64 <<= FRACTIONBITS;
769 DataSize64 -= increment;
770 DataSize64 -= DataPosFrac;
772 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
773 BufferSize = minu(BufferSize, (SamplesToDo-OutPos));
775 SrcData += BufferPrePadding*FrameSize;
776 Source->Params.DoMix(Source, Device, SrcData, &DataPosInt, &DataPosFrac,
777 OutPos, SamplesToDo, BufferSize);
778 OutPos += BufferSize;
780 /* Handle looping sources */
781 while(1)
782 {
783 const ALbuffer *ALBuffer;
784 ALuint DataSize = 0;
785 ALuint LoopStart = 0;
786 ALuint LoopEnd = 0;
788 if((ALBuffer=BufferListItem->buffer) != NULL)
789 {
790 DataSize = ALBuffer->size / FrameSize;
791 LoopStart = ALBuffer->LoopStart;
792 LoopEnd = ALBuffer->LoopEnd;
793 if(LoopEnd > DataPosInt)
794 break;
795 }
797 if(Looping && Source->lSourceType == AL_STATIC)
798 {
799 BufferListItem = Source->queue;
800 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
801 break;
802 }
804 if(DataSize > DataPosInt)
805 break;
807 if(BufferListItem->next)
808 {
809 BufferListItem = BufferListItem->next;
810 BuffersPlayed++;
811 }
812 else if(Looping)
813 {
814 BufferListItem = Source->queue;
815 BuffersPlayed = 0;
816 }
817 else
818 {
819 State = AL_STOPPED;
820 BufferListItem = Source->queue;
821 BuffersPlayed = Source->BuffersInQueue;
822 DataPosInt = 0;
823 DataPosFrac = 0;
824 break;
825 }
827 DataPosInt -= DataSize;
828 }
829 } while(State == AL_PLAYING && OutPos < SamplesToDo);
831 /* Update source info */
832 Source->state = State;
833 Source->BuffersPlayed = BuffersPlayed;
834 Source->position = DataPosInt;
835 Source->position_fraction = DataPosFrac;
836 Source->Buffer = BufferListItem->buffer;
837 Source->HrtfOffset += OutPos;
838 if(State == AL_PLAYING)
839 {
840 Source->HrtfCounter = maxu(Source->HrtfCounter, OutPos) - OutPos;
841 Source->HrtfMoving = AL_TRUE;
842 }
843 else
844 {
845 Source->HrtfCounter = 0;
846 Source->HrtfMoving = AL_FALSE;
847 }
848 }