Mercurial > audio-send
comparison Alc/mixer.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f9476ff7637e |
---|---|
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 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #include <math.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 #include <ctype.h> | |
27 #include <assert.h> | |
28 | |
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" | |
38 | |
39 | |
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)); } | |
47 | |
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); } | |
55 | |
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); } | |
63 | |
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 | |
71 | |
72 #if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_H) | |
73 #include <arm_neon.h> | |
74 | |
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]); | |
94 | |
95 vals = vmlaq_f32(vals, coefs, leftright4); | |
96 | |
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 } | |
101 | |
102 #else | |
103 | |
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 } | |
116 | |
117 #endif | |
118 | |
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 } | |
316 | |
317 DECL_TEMPLATE(ALfloat, point32) | |
318 DECL_TEMPLATE(ALfloat, lerp32) | |
319 DECL_TEMPLATE(ALfloat, cubic32) | |
320 | |
321 DECL_TEMPLATE(ALshort, point16) | |
322 DECL_TEMPLATE(ALshort, lerp16) | |
323 DECL_TEMPLATE(ALshort, cubic16) | |
324 | |
325 DECL_TEMPLATE(ALbyte, point8) | |
326 DECL_TEMPLATE(ALbyte, lerp8) | |
327 DECL_TEMPLATE(ALbyte, cubic8) | |
328 | |
329 #undef DECL_TEMPLATE | |
330 | |
331 | |
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 } | |
456 | |
457 DECL_TEMPLATE(ALfloat, point32) | |
458 DECL_TEMPLATE(ALfloat, lerp32) | |
459 DECL_TEMPLATE(ALfloat, cubic32) | |
460 | |
461 DECL_TEMPLATE(ALshort, point16) | |
462 DECL_TEMPLATE(ALshort, lerp16) | |
463 DECL_TEMPLATE(ALshort, cubic16) | |
464 | |
465 DECL_TEMPLATE(ALbyte, point8) | |
466 DECL_TEMPLATE(ALbyte, lerp8) | |
467 DECL_TEMPLATE(ALbyte, cubic8) | |
468 | |
469 #undef DECL_TEMPLATE | |
470 | |
471 | |
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 } | |
486 | |
487 DECL_TEMPLATE(point) | |
488 DECL_TEMPLATE(lerp) | |
489 DECL_TEMPLATE(cubic) | |
490 | |
491 #undef DECL_TEMPLATE | |
492 | |
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 } | |
509 | |
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 } | |
524 | |
525 DECL_TEMPLATE(point) | |
526 DECL_TEMPLATE(lerp) | |
527 DECL_TEMPLATE(cubic) | |
528 | |
529 #undef DECL_TEMPLATE | |
530 | |
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 } | |
547 | |
548 | |
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; | |
562 | |
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; | |
572 | |
573 /* Get current buffer queue item */ | |
574 BufferListItem = Source->queue; | |
575 for(i = 0;i < BuffersPlayed;i++) | |
576 BufferListItem = BufferListItem->next; | |
577 | |
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; | |
586 | |
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; | |
594 | |
595 BufferSize = ((DataSize64 > STACK_DATA_SIZE) ? STACK_DATA_SIZE : DataSize64); | |
596 BufferSize -= BufferSize%FrameSize; | |
597 | |
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; | |
604 | |
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; | |
609 | |
610 if(DataPosInt >= BufferPrePadding) | |
611 pos = (DataPosInt-BufferPrePadding)*FrameSize; | |
612 else | |
613 { | |
614 DataSize = (BufferPrePadding-DataPosInt)*FrameSize; | |
615 DataSize = minu(BufferSize, DataSize); | |
616 | |
617 memset(&SrcData[SrcDataSize], 0, DataSize); | |
618 SrcDataSize += DataSize; | |
619 BufferSize -= DataSize; | |
620 | |
621 pos = 0; | |
622 } | |
623 | |
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); | |
628 | |
629 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize); | |
630 SrcDataSize += DataSize; | |
631 BufferSize -= DataSize; | |
632 | |
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; | |
641 | |
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); | |
657 | |
658 memset(&SrcData[SrcDataSize], 0, DataSize); | |
659 SrcDataSize += DataSize; | |
660 BufferSize -= DataSize; | |
661 | |
662 pos = 0; | |
663 } | |
664 | |
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); | |
669 | |
670 memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize); | |
671 SrcDataSize += DataSize; | |
672 BufferSize -= DataSize; | |
673 | |
674 DataSize = (LoopEnd-LoopStart) * FrameSize; | |
675 while(BufferSize > 0) | |
676 { | |
677 DataSize = minu(BufferSize, DataSize); | |
678 | |
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; | |
690 | |
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); | |
701 | |
702 memset(&SrcData[SrcDataSize], 0, DataSize); | |
703 SrcDataSize += DataSize; | |
704 BufferSize -= DataSize; | |
705 | |
706 pos = 0; | |
707 break; | |
708 } | |
709 | |
710 if(BufferListIter->prev) | |
711 BufferListIter = BufferListIter->prev; | |
712 else | |
713 { | |
714 while(BufferListIter->next) | |
715 BufferListIter = BufferListIter->next; | |
716 } | |
717 | |
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 } | |
729 | |
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; | |
737 | |
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; | |
746 | |
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 } | |
764 | |
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; | |
771 | |
772 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment); | |
773 BufferSize = minu(BufferSize, (SamplesToDo-OutPos)); | |
774 | |
775 SrcData += BufferPrePadding*FrameSize; | |
776 Source->Params.DoMix(Source, Device, SrcData, &DataPosInt, &DataPosFrac, | |
777 OutPos, SamplesToDo, BufferSize); | |
778 OutPos += BufferSize; | |
779 | |
780 /* Handle looping sources */ | |
781 while(1) | |
782 { | |
783 const ALbuffer *ALBuffer; | |
784 ALuint DataSize = 0; | |
785 ALuint LoopStart = 0; | |
786 ALuint LoopEnd = 0; | |
787 | |
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 } | |
796 | |
797 if(Looping && Source->lSourceType == AL_STATIC) | |
798 { | |
799 BufferListItem = Source->queue; | |
800 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; | |
801 break; | |
802 } | |
803 | |
804 if(DataSize > DataPosInt) | |
805 break; | |
806 | |
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 } | |
826 | |
827 DataPosInt -= DataSize; | |
828 } | |
829 } while(State == AL_PLAYING && OutPos < SamplesToDo); | |
830 | |
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 } |