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 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); }
65 #define LIKELY(x) __builtin_expect(!!(x), 1)
66 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
69 #define UNLIKELY(x) (x)
72 #define DECL_TEMPLATE(T, sampler) \
73 static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
74 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
75 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
77 const ALuint NumChannels = Source->NumChannels; \
78 const T *RESTRICT data = srcdata; \
79 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \
80 ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \
88 increment = Source->Params.Step; \
90 DryBuffer = Device->DryBuffer; \
91 ClickRemoval = Device->ClickRemoval; \
92 PendingClicks = Device->PendingClicks; \
93 DryFilter = &Source->Params.iirFilter; \
96 frac = *DataPosFrac; \
98 for(i = 0;i < NumChannels;i++) \
100 ALfloat (*RESTRICT Coeffs)[2] = Source->Params.HrtfCoeffs[i]; \
101 const ALuint *RESTRICT Delay = Source->Params.HrtfDelay[i]; \
102 ALfloat *RESTRICT History = Source->HrtfHistory[i]; \
103 ALfloat (*RESTRICT Values)[2] = Source->HrtfValues[i]; \
104 ALuint Offset = Source->HrtfOffset + OutPos; \
105 ALfloat left, right; \
108 frac = *DataPosFrac; \
110 if(LIKELY(OutPos == 0)) \
112 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
113 value = lpFilter2PC(DryFilter, i, value); \
115 History[Offset&SRC_HISTORY_MASK] = value; \
116 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
117 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
119 ClickRemoval[FRONT_LEFT] -= Values[(Offset+1)&HRIR_MASK][0] + \
120 Coeffs[0][0] * left; \
121 ClickRemoval[FRONT_RIGHT] -= Values[(Offset+1)&HRIR_MASK][1] + \
122 Coeffs[0][1] * right; \
124 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
126 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
127 value = lpFilter2P(DryFilter, i, value); \
129 History[Offset&SRC_HISTORY_MASK] = value; \
130 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
131 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
133 Values[Offset&HRIR_MASK][0] = 0.0f; \
134 Values[Offset&HRIR_MASK][1] = 0.0f; \
137 for(c = 0;c < HRIR_LENGTH;c++) \
139 const ALuint off = (Offset+c)&HRIR_MASK; \
140 Values[off][0] += Coeffs[c][0] * left; \
141 Values[off][1] += Coeffs[c][1] * right; \
144 DryBuffer[OutPos][FRONT_LEFT] += Values[Offset&HRIR_MASK][0]; \
145 DryBuffer[OutPos][FRONT_RIGHT] += Values[Offset&HRIR_MASK][1]; \
148 pos += frac>>FRACTIONBITS; \
149 frac &= FRACTIONMASK; \
152 if(LIKELY(OutPos == SamplesToDo)) \
154 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
155 value = lpFilter2PC(DryFilter, i, value); \
157 History[Offset&SRC_HISTORY_MASK] = value; \
158 left = History[(Offset-Delay[0])&SRC_HISTORY_MASK]; \
159 right = History[(Offset-Delay[1])&SRC_HISTORY_MASK]; \
161 PendingClicks[FRONT_LEFT] += Values[(Offset+1)&HRIR_MASK][0] + \
162 Coeffs[0][0] * left; \
163 PendingClicks[FRONT_RIGHT] += Values[(Offset+1)&HRIR_MASK][1] + \
164 Coeffs[0][1] * right; \
166 OutPos -= BufferSize; \
169 for(out = 0;out < Device->NumAuxSends;out++) \
171 ALeffectslot *Slot = Source->Params.Send[i].Slot; \
173 ALfloat *RESTRICT WetBuffer; \
174 ALfloat *RESTRICT WetClickRemoval; \
175 ALfloat *RESTRICT WetPendingClicks; \
178 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
181 WetBuffer = Slot->WetBuffer; \
182 WetClickRemoval = Slot->ClickRemoval; \
183 WetPendingClicks = Slot->PendingClicks; \
184 WetFilter = &Source->Params.Send[out].iirFilter; \
185 WetSend = Source->Params.Send[out].WetGain; \
187 for(i = 0;i < NumChannels;i++) \
190 frac = *DataPosFrac; \
192 if(LIKELY(OutPos == 0)) \
194 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
195 value = lpFilter1PC(WetFilter, i, value); \
197 WetClickRemoval[0] -= value * WetSend; \
199 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
201 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
202 value = lpFilter1P(WetFilter, i, value); \
204 WetBuffer[OutPos] += value * WetSend; \
207 pos += frac>>FRACTIONBITS; \
208 frac &= FRACTIONMASK; \
211 if(LIKELY(OutPos == SamplesToDo)) \
213 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
214 value = lpFilter1PC(WetFilter, i, value); \
216 WetPendingClicks[0] += value * WetSend; \
218 OutPos -= BufferSize; \
221 *DataPosInt += pos; \
222 *DataPosFrac = frac; \
225 DECL_TEMPLATE(ALfloat
, point32
)
226 DECL_TEMPLATE(ALfloat
, lerp32
)
227 DECL_TEMPLATE(ALfloat
, cubic32
)
229 DECL_TEMPLATE(ALshort
, point16
)
230 DECL_TEMPLATE(ALshort
, lerp16
)
231 DECL_TEMPLATE(ALshort
, cubic16
)
233 DECL_TEMPLATE(ALbyte
, point8
)
234 DECL_TEMPLATE(ALbyte
, lerp8
)
235 DECL_TEMPLATE(ALbyte
, cubic8
)
240 #define DECL_TEMPLATE(T, sampler) \
241 static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device, \
242 const ALvoid *srcdata, ALuint *DataPosInt, ALuint *DataPosFrac, \
243 ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize) \
245 const ALuint NumChannels = Source->NumChannels; \
246 const T *RESTRICT data = srcdata; \
247 ALfloat (*DryBuffer)[MAXCHANNELS]; \
248 ALfloat *ClickRemoval, *PendingClicks; \
250 ALfloat DrySend[MAXCHANNELS][MAXCHANNELS]; \
257 increment = Source->Params.Step; \
259 DryBuffer = Device->DryBuffer; \
260 ClickRemoval = Device->ClickRemoval; \
261 PendingClicks = Device->PendingClicks; \
262 DryFilter = &Source->Params.iirFilter; \
263 for(i = 0;i < NumChannels;i++) \
265 for(c = 0;c < MAXCHANNELS;c++) \
266 DrySend[i][c] = Source->Params.DryGains[i][c]; \
270 frac = *DataPosFrac; \
272 for(i = 0;i < NumChannels;i++) \
275 frac = *DataPosFrac; \
279 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
281 value = lpFilter2PC(DryFilter, i, value); \
282 for(c = 0;c < MAXCHANNELS;c++) \
283 ClickRemoval[c] -= value*DrySend[i][c]; \
285 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
287 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
289 value = lpFilter2P(DryFilter, i, value); \
290 for(c = 0;c < MAXCHANNELS;c++) \
291 DryBuffer[OutPos][c] += value*DrySend[i][c]; \
294 pos += frac>>FRACTIONBITS; \
295 frac &= FRACTIONMASK; \
298 if(OutPos == SamplesToDo) \
300 value = sampler(data + pos*NumChannels + i, NumChannels, frac); \
302 value = lpFilter2PC(DryFilter, i, value); \
303 for(c = 0;c < MAXCHANNELS;c++) \
304 PendingClicks[c] += value*DrySend[i][c]; \
306 OutPos -= BufferSize; \
309 for(out = 0;out < Device->NumAuxSends;out++) \
311 ALeffectslot *Slot = Source->Params.Send[i].Slot; \
313 ALfloat *WetBuffer; \
314 ALfloat *WetClickRemoval; \
315 ALfloat *WetPendingClicks; \
318 if(!Slot || Slot->effect.type == AL_EFFECT_NULL) \
321 WetBuffer = Slot->WetBuffer; \
322 WetClickRemoval = Slot->ClickRemoval; \
323 WetPendingClicks = Slot->PendingClicks; \
324 WetFilter = &Source->Params.Send[out].iirFilter; \
325 WetSend = Source->Params.Send[out].WetGain; \
327 for(i = 0;i < NumChannels;i++) \
330 frac = *DataPosFrac; \
334 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
336 value = lpFilter1PC(WetFilter, i, value); \
337 WetClickRemoval[0] -= value * WetSend; \
339 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
341 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
343 value = lpFilter1P(WetFilter, i, value); \
344 WetBuffer[OutPos] += value * WetSend; \
347 pos += frac>>FRACTIONBITS; \
348 frac &= FRACTIONMASK; \
351 if(OutPos == SamplesToDo) \
353 value = sampler(data + pos*NumChannels + i, NumChannels,frac);\
355 value = lpFilter1PC(WetFilter, i, value); \
356 WetPendingClicks[0] += value * WetSend; \
358 OutPos -= BufferSize; \
361 *DataPosInt += pos; \
362 *DataPosFrac = frac; \
365 DECL_TEMPLATE(ALfloat
, point32
)
366 DECL_TEMPLATE(ALfloat
, lerp32
)
367 DECL_TEMPLATE(ALfloat
, cubic32
)
369 DECL_TEMPLATE(ALshort
, point16
)
370 DECL_TEMPLATE(ALshort
, lerp16
)
371 DECL_TEMPLATE(ALshort
, cubic16
)
373 DECL_TEMPLATE(ALbyte
, point8
)
374 DECL_TEMPLATE(ALbyte
, lerp8
)
375 DECL_TEMPLATE(ALbyte
, cubic8
)
380 #define DECL_TEMPLATE(sampler) \
381 static MixerFunc Select_##sampler(enum FmtType FmtType) \
386 return Mix_ALbyte_##sampler##8; \
388 return Mix_ALshort_##sampler##16; \
390 return Mix_ALfloat_##sampler##32; \
401 MixerFunc
SelectMixer(ALbuffer
*Buffer
, enum Resampler Resampler
)
405 case POINT_RESAMPLER
:
406 return Select_point(Buffer
->FmtType
);
407 case LINEAR_RESAMPLER
:
408 return Select_lerp(Buffer
->FmtType
);
409 case CUBIC_RESAMPLER
:
410 return Select_cubic(Buffer
->FmtType
);
418 #define DECL_TEMPLATE(sampler) \
419 static MixerFunc Select_Hrtf_##sampler(enum FmtType FmtType) \
424 return Mix_Hrtf_ALbyte_##sampler##8; \
426 return Mix_Hrtf_ALshort_##sampler##16; \
428 return Mix_Hrtf_ALfloat_##sampler##32; \
439 MixerFunc
SelectHrtfMixer(ALbuffer
*Buffer
, enum Resampler Resampler
)
443 case POINT_RESAMPLER
:
444 return Select_Hrtf_point(Buffer
->FmtType
);
445 case LINEAR_RESAMPLER
:
446 return Select_Hrtf_lerp(Buffer
->FmtType
);
447 case CUBIC_RESAMPLER
:
448 return Select_Hrtf_cubic(Buffer
->FmtType
);
457 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
459 ALbufferlistitem
*BufferListItem
;
460 ALuint DataPosInt
, DataPosFrac
;
461 ALuint BuffersPlayed
;
464 enum Resampler Resampler
;
471 /* Get source info */
472 State
= Source
->state
;
473 BuffersPlayed
= Source
->BuffersPlayed
;
474 DataPosInt
= Source
->position
;
475 DataPosFrac
= Source
->position_fraction
;
476 Looping
= Source
->bLooping
;
477 increment
= Source
->Params
.Step
;
478 Resampler
= Source
->Resampler
;
479 FrameSize
= Source
->NumChannels
* Source
->SampleSize
;
481 /* Get current buffer queue item */
482 BufferListItem
= Source
->queue
;
483 for(i
= 0;i
< BuffersPlayed
;i
++)
484 BufferListItem
= BufferListItem
->next
;
488 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
489 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
490 ALubyte StackData
[STACK_DATA_SIZE
];
491 ALubyte
*SrcData
= StackData
;
492 ALuint SrcDataSize
= 0;
495 /* Figure out how many buffer bytes will be needed */
496 DataSize64
= SamplesToDo
-OutPos
+1;
497 DataSize64
*= increment
;
498 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
499 DataSize64
>>= FRACTIONBITS
;
500 DataSize64
+= BufferPadding
+BufferPrePadding
;
501 DataSize64
*= FrameSize
;
503 BufferSize
= min(DataSize64
, STACK_DATA_SIZE
);
504 BufferSize
-= BufferSize
%FrameSize
;
506 if(Source
->lSourceType
== AL_STATIC
)
508 const ALbuffer
*ALBuffer
= Source
->Buffer
;
509 const ALubyte
*Data
= ALBuffer
->data
;
513 /* If current pos is beyond the loop range, do not loop */
514 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
518 if(DataPosInt
>= BufferPrePadding
)
519 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
522 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
523 DataSize
= min(BufferSize
, DataSize
);
525 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
526 SrcDataSize
+= DataSize
;
527 BufferSize
-= DataSize
;
532 /* Copy what's left to play in the source buffer, and clear the
533 * rest of the temp buffer */
534 DataSize
= ALBuffer
->size
- pos
;
535 DataSize
= min(BufferSize
, DataSize
);
537 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
538 SrcDataSize
+= DataSize
;
539 BufferSize
-= DataSize
;
541 memset(&SrcData
[SrcDataSize
], 0, BufferSize
);
542 SrcDataSize
+= BufferSize
;
543 BufferSize
-= BufferSize
;
547 ALuint LoopStart
= ALBuffer
->LoopStart
;
548 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
550 if(DataPosInt
>= LoopStart
)
552 pos
= DataPosInt
-LoopStart
;
553 while(pos
< BufferPrePadding
)
554 pos
+= LoopEnd
-LoopStart
;
555 pos
-= BufferPrePadding
;
559 else if(DataPosInt
>= BufferPrePadding
)
560 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
563 DataSize
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
564 DataSize
= min(BufferSize
, DataSize
);
566 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
567 SrcDataSize
+= DataSize
;
568 BufferSize
-= DataSize
;
573 /* Copy what's left of this loop iteration, then copy repeats
574 * of the loop section */
575 DataSize
= LoopEnd
*FrameSize
- pos
;
576 DataSize
= min(BufferSize
, DataSize
);
578 memcpy(&SrcData
[SrcDataSize
], &Data
[pos
], DataSize
);
579 SrcDataSize
+= DataSize
;
580 BufferSize
-= DataSize
;
582 DataSize
= (LoopEnd
-LoopStart
) * FrameSize
;
583 while(BufferSize
> 0)
585 DataSize
= min(BufferSize
, DataSize
);
587 memcpy(&SrcData
[SrcDataSize
], &Data
[LoopStart
*FrameSize
], DataSize
);
588 SrcDataSize
+= DataSize
;
589 BufferSize
-= DataSize
;
595 /* Crawl the buffer queue to fill in the temp buffer */
596 ALbufferlistitem
*BufferListIter
= BufferListItem
;
599 if(DataPosInt
>= BufferPrePadding
)
600 pos
= (DataPosInt
-BufferPrePadding
)*FrameSize
;
603 pos
= (BufferPrePadding
-DataPosInt
)*FrameSize
;
606 if(!BufferListIter
->prev
&& !Looping
)
608 ALuint DataSize
= min(BufferSize
, pos
);
610 memset(&SrcData
[SrcDataSize
], 0, DataSize
);
611 SrcDataSize
+= DataSize
;
612 BufferSize
-= DataSize
;
618 if(BufferListIter
->prev
)
619 BufferListIter
= BufferListIter
->prev
;
622 while(BufferListIter
->next
)
623 BufferListIter
= BufferListIter
->next
;
626 if(BufferListIter
->buffer
)
628 if((ALuint
)BufferListIter
->buffer
->size
> pos
)
630 pos
= BufferListIter
->buffer
->size
- pos
;
633 pos
-= BufferListIter
->buffer
->size
;
638 while(BufferListIter
&& BufferSize
> 0)
640 const ALbuffer
*ALBuffer
;
641 if((ALBuffer
=BufferListIter
->buffer
) != NULL
)
643 const ALubyte
*Data
= ALBuffer
->data
;
644 ALuint DataSize
= ALBuffer
->size
;
646 /* Skip the data already played */
655 DataSize
= min(BufferSize
, DataSize
);
656 memcpy(&SrcData
[SrcDataSize
], Data
, DataSize
);
657 SrcDataSize
+= DataSize
;
658 BufferSize
-= DataSize
;
661 BufferListIter
= BufferListIter
->next
;
662 if(!BufferListIter
&& Looping
)
663 BufferListIter
= Source
->queue
;
664 else if(!BufferListIter
)
666 memset(&SrcData
[SrcDataSize
], 0, BufferSize
);
667 SrcDataSize
+= BufferSize
;
668 BufferSize
-= BufferSize
;
673 /* Figure out how many samples we can mix. */
674 DataSize64
= SrcDataSize
/ FrameSize
;
675 DataSize64
-= BufferPadding
+BufferPrePadding
;
676 DataSize64
<<= FRACTIONBITS
;
677 DataSize64
-= increment
;
678 DataSize64
-= DataPosFrac
;
680 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
681 BufferSize
= min(BufferSize
, (SamplesToDo
-OutPos
));
683 SrcData
+= BufferPrePadding
*FrameSize
;
684 Source
->Params
.DoMix(Source
, Device
, SrcData
, &DataPosInt
, &DataPosFrac
,
685 OutPos
, SamplesToDo
, BufferSize
);
686 OutPos
+= BufferSize
;
688 /* Handle looping sources */
691 const ALbuffer
*ALBuffer
;
693 ALuint LoopStart
= 0;
696 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
698 DataSize
= ALBuffer
->size
/ FrameSize
;
699 LoopStart
= ALBuffer
->LoopStart
;
700 LoopEnd
= ALBuffer
->LoopEnd
;
701 if(LoopEnd
> DataPosInt
)
705 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
707 BufferListItem
= Source
->queue
;
708 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
712 if(DataSize
> DataPosInt
)
715 if(BufferListItem
->next
)
717 BufferListItem
= BufferListItem
->next
;
722 BufferListItem
= Source
->queue
;
728 BufferListItem
= Source
->queue
;
729 BuffersPlayed
= Source
->BuffersInQueue
;
735 DataPosInt
-= DataSize
;
737 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
739 /* Update source info */
740 Source
->state
= State
;
741 Source
->BuffersPlayed
= BuffersPlayed
;
742 Source
->position
= DataPosInt
;
743 Source
->position_fraction
= DataPosFrac
;
744 Source
->Buffer
= BufferListItem
->buffer
;
745 Source
->HrtfOffset
+= OutPos
;