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 ALfloat
Sample_ALbyte(ALbyte val
)
41 { return val
* (1.0f
/127.0f
); }
43 static __inline ALfloat
Sample_ALshort(ALshort val
)
44 { return val
* (1.0f
/32767.0f
); }
46 static __inline ALfloat
Sample_ALfloat(ALfloat val
)
49 #define DECL_TEMPLATE(T) \
50 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
53 for(i = 0;i < samples;i++) \
54 dst[i] = Sample_##T(src[i]); \
58 DECL_TEMPLATE(ALshort
)
59 DECL_TEMPLATE(ALfloat
)
63 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, enum FmtType srctype
, ALuint samples
)
68 Load_ALbyte(dst
, src
, samples
);
71 Load_ALshort(dst
, src
, samples
);
74 Load_ALfloat(dst
, src
, samples
);
79 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
82 for(i
= 0;i
< samples
;i
++)
87 static __inline ALfloat
point32(const ALfloat
*vals
, ALint step
, ALint frac
)
88 { return vals
[0]; (void)step
; (void)frac
; }
89 static __inline ALfloat
lerp32(const ALfloat
*vals
, ALint step
, ALint frac
)
90 { return lerp(vals
[0], vals
[step
], frac
* (1.0f
/FRACTIONONE
)); }
91 static __inline ALfloat
cubic32(const ALfloat
*vals
, ALint step
, ALint frac
)
92 { return cubic(vals
[-step
], vals
[0], vals
[step
], vals
[step
+step
],
93 frac
* (1.0f
/FRACTIONONE
)); }
95 #define DECL_TEMPLATE(Sampler) \
96 static void Resample_##Sampler(const ALfloat *data, ALuint frac, \
97 ALuint increment, ALuint NumChannels, ALfloat *RESTRICT OutBuffer, \
104 for(i = 0;i < BufferSize+1;i++) \
106 value = Sampler(data + pos*NumChannels, NumChannels, frac); \
107 OutBuffer[i] = value; \
110 pos += frac>>FRACTIONBITS; \
111 frac &= FRACTIONMASK; \
115 DECL_TEMPLATE(point32
)
116 DECL_TEMPLATE(lerp32
)
117 DECL_TEMPLATE(cubic32
)
121 static void Resample(enum Resampler Resampler
, const ALfloat
*data
, ALuint frac
,
122 ALuint increment
, ALuint NumChannels
,
123 ALfloat
*RESTRICT OutBuffer
, ALuint BufferSize
)
125 if(increment
== FRACTIONONE
)
131 Resample_point32(data
, frac
, increment
, NumChannels
,
132 OutBuffer
, BufferSize
);
134 case LinearResampler
:
135 Resample_lerp32(data
, frac
, increment
, NumChannels
,
136 OutBuffer
, BufferSize
);
139 Resample_cubic32(data
, frac
, increment
, NumChannels
,
140 OutBuffer
, BufferSize
);
143 /* Shouldn't happen */
149 static void Filter2P(FILTER
*filter
, ALuint chan
, ALfloat
*RESTRICT dst
,
150 const ALfloat
*RESTRICT src
, ALuint numsamples
)
153 for(i
= 0;i
< numsamples
;i
++)
154 dst
[i
] = lpFilter2P(filter
, chan
, src
[i
]);
155 dst
[i
] = lpFilter2PC(filter
, chan
, src
[i
]);
159 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
161 ALbufferlistitem
*BufferListItem
;
162 ALuint DataPosInt
, DataPosFrac
;
163 ALuint BuffersPlayed
;
166 enum Resampler Resampler
;
174 /* Get source info */
175 State
= Source
->state
;
176 BuffersPlayed
= Source
->BuffersPlayed
;
177 DataPosInt
= Source
->position
;
178 DataPosFrac
= Source
->position_fraction
;
179 Looping
= Source
->Looping
;
180 increment
= Source
->Params
.Step
;
181 Resampler
= Source
->Resampler
;
182 NumChannels
= Source
->NumChannels
;
183 FrameSize
= NumChannels
* Source
->SampleSize
;
185 /* Get current buffer queue item */
186 BufferListItem
= Source
->queue
;
187 for(i
= 0;i
< BuffersPlayed
;i
++)
188 BufferListItem
= BufferListItem
->next
;
192 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
193 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
194 ALfloat StackData
[BUFFERSIZE
];
195 ALfloat
*SrcData
= StackData
;
196 ALuint SrcDataSize
= 0;
199 /* Figure out how many buffer bytes will be needed */
200 DataSize64
= SamplesToDo
-OutPos
+1;
201 DataSize64
*= increment
;
202 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
203 DataSize64
>>= FRACTIONBITS
;
204 DataSize64
+= BufferPadding
+BufferPrePadding
;
205 DataSize64
*= NumChannels
;
207 BufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
208 BufferSize
/= NumChannels
;
210 if(Source
->SourceType
== AL_STATIC
)
212 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
213 const ALubyte
*Data
= ALBuffer
->data
;
217 /* If current pos is beyond the loop range, do not loop */
218 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
222 if(DataPosInt
>= BufferPrePadding
)
223 pos
= DataPosInt
- BufferPrePadding
;
226 DataSize
= BufferPrePadding
- DataPosInt
;
227 DataSize
= minu(BufferSize
, DataSize
);
229 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
230 DataSize
*NumChannels
);
231 SrcDataSize
+= DataSize
;
232 BufferSize
-= DataSize
;
237 /* Copy what's left to play in the source buffer, and clear the
238 * rest of the temp buffer */
239 DataSize
= ALBuffer
->SampleLen
- pos
;
240 DataSize
= minu(BufferSize
, DataSize
);
242 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
243 ALBuffer
->FmtType
, DataSize
*NumChannels
);
244 SrcDataSize
+= DataSize
;
245 BufferSize
-= DataSize
;
247 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
],
248 BufferSize
*NumChannels
);
249 SrcDataSize
+= BufferSize
;
250 BufferSize
-= BufferSize
;
254 ALuint LoopStart
= ALBuffer
->LoopStart
;
255 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
257 if(DataPosInt
>= LoopStart
)
259 pos
= DataPosInt
-LoopStart
;
260 while(pos
< BufferPrePadding
)
261 pos
+= LoopEnd
-LoopStart
;
262 pos
-= BufferPrePadding
;
265 else if(DataPosInt
>= BufferPrePadding
)
266 pos
= DataPosInt
- BufferPrePadding
;
269 DataSize
= BufferPrePadding
- DataPosInt
;
270 DataSize
= minu(BufferSize
, DataSize
);
272 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
273 SrcDataSize
+= DataSize
;
274 BufferSize
-= DataSize
;
279 /* Copy what's left of this loop iteration, then copy repeats
280 * of the loop section */
281 DataSize
= LoopEnd
- pos
;
282 DataSize
= minu(BufferSize
, DataSize
);
284 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[pos
*FrameSize
],
285 ALBuffer
->FmtType
, DataSize
*NumChannels
);
286 SrcDataSize
+= DataSize
;
287 BufferSize
-= DataSize
;
289 DataSize
= LoopEnd
-LoopStart
;
290 while(BufferSize
> 0)
292 DataSize
= minu(BufferSize
, DataSize
);
294 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], &Data
[LoopStart
*FrameSize
],
295 ALBuffer
->FmtType
, DataSize
*NumChannels
);
296 SrcDataSize
+= DataSize
;
297 BufferSize
-= DataSize
;
303 /* Crawl the buffer queue to fill in the temp buffer */
304 ALbufferlistitem
*tmpiter
= BufferListItem
;
307 if(DataPosInt
>= BufferPrePadding
)
308 pos
= DataPosInt
- BufferPrePadding
;
311 pos
= BufferPrePadding
- DataPosInt
;
314 if(!tmpiter
->prev
&& !Looping
)
316 ALuint DataSize
= minu(BufferSize
, pos
);
318 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], DataSize
*NumChannels
);
319 SrcDataSize
+= DataSize
;
320 BufferSize
-= DataSize
;
327 tmpiter
= tmpiter
->prev
;
331 tmpiter
= tmpiter
->next
;
336 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
338 pos
= tmpiter
->buffer
->SampleLen
- pos
;
341 pos
-= tmpiter
->buffer
->SampleLen
;
346 while(tmpiter
&& BufferSize
> 0)
348 const ALbuffer
*ALBuffer
;
349 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
351 const ALubyte
*Data
= ALBuffer
->data
;
352 ALuint DataSize
= ALBuffer
->SampleLen
;
354 /* Skip the data already played */
359 Data
+= pos
*FrameSize
;
363 DataSize
= minu(BufferSize
, DataSize
);
364 LoadStack(&SrcData
[SrcDataSize
*NumChannels
], Data
,
365 ALBuffer
->FmtType
, DataSize
*NumChannels
);
366 SrcDataSize
+= DataSize
;
367 BufferSize
-= DataSize
;
370 tmpiter
= tmpiter
->next
;
371 if(!tmpiter
&& Looping
)
372 tmpiter
= Source
->queue
;
375 SilenceStack(&SrcData
[SrcDataSize
*NumChannels
], BufferSize
*NumChannels
);
376 SrcDataSize
+= BufferSize
;
377 BufferSize
-= BufferSize
;
382 /* Figure out how many samples we can mix. */
383 DataSize64
= SrcDataSize
;
384 DataSize64
-= BufferPadding
+BufferPrePadding
;
385 DataSize64
<<= FRACTIONBITS
;
386 DataSize64
-= increment
;
387 DataSize64
-= DataPosFrac
;
389 BufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
390 BufferSize
= minu(BufferSize
, (SamplesToDo
-OutPos
));
392 /* Some mixers like having a multiple of 4, so try to give that unless
393 * this is the last update. */
394 if(OutPos
+BufferSize
< SamplesToDo
)
397 SrcData
+= BufferPrePadding
*NumChannels
;
398 for(i
= 0;i
< NumChannels
;i
++)
400 DirectParams
*directparms
= &Source
->Params
.Direct
;
401 ALIGN(16) ALfloat FilteredData
[BUFFERSIZE
];
402 ALfloat ResampledData
[BUFFERSIZE
];
404 Resample(Resampler
, SrcData
+i
, DataPosFrac
, increment
,
405 NumChannels
, ResampledData
, BufferSize
);
407 Filter2P(&directparms
->iirFilter
, i
, FilteredData
, ResampledData
,
409 Source
->Params
.DryMix(Source
, Device
, directparms
,
410 FilteredData
, i
, OutPos
, SamplesToDo
,
413 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
415 SendParams
*sendparms
= &Source
->Params
.Send
[j
];
419 Filter2P(&sendparms
->iirFilter
, i
, FilteredData
, ResampledData
,
421 Source
->Params
.WetMix(sendparms
, FilteredData
, OutPos
,
422 SamplesToDo
, BufferSize
);
425 for(i
= 0;i
< BufferSize
;i
++)
427 DataPosFrac
+= increment
;
428 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
429 DataPosFrac
&= FRACTIONMASK
;
433 /* Handle looping sources */
436 const ALbuffer
*ALBuffer
;
438 ALuint LoopStart
= 0;
441 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
443 DataSize
= ALBuffer
->SampleLen
;
444 LoopStart
= ALBuffer
->LoopStart
;
445 LoopEnd
= ALBuffer
->LoopEnd
;
446 if(LoopEnd
> DataPosInt
)
450 if(Looping
&& Source
->SourceType
== AL_STATIC
)
452 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
456 if(DataSize
> DataPosInt
)
459 if(BufferListItem
->next
)
461 BufferListItem
= BufferListItem
->next
;
466 BufferListItem
= Source
->queue
;
472 BufferListItem
= Source
->queue
;
473 BuffersPlayed
= Source
->BuffersInQueue
;
479 DataPosInt
-= DataSize
;
481 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
483 /* Update source info */
484 Source
->state
= State
;
485 Source
->BuffersPlayed
= BuffersPlayed
;
486 Source
->position
= DataPosInt
;
487 Source
->position_fraction
= DataPosFrac
;
488 Source
->Hrtf
.Offset
+= OutPos
;
489 if(State
== AL_PLAYING
)
491 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
492 Source
->Hrtf
.Moving
= AL_TRUE
;
496 Source
->Hrtf
.Counter
= 0;
497 Source
->Hrtf
.Moving
= AL_FALSE
;