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 extern inline void InitiatePositionArrays(ALuint frac
, ALuint increment
, ALuint
*frac_arr
, ALuint
*pos_arr
, ALuint size
);
43 static inline ALfloat
Sample_ALbyte(ALbyte val
)
44 { return val
* (1.0f
/127.0f
); }
46 static inline ALfloat
Sample_ALshort(ALshort val
)
47 { return val
* (1.0f
/32767.0f
); }
49 static inline ALfloat
Sample_ALfloat(ALfloat val
)
52 #define DECL_TEMPLATE(T) \
53 static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
56 for(i = 0;i < samples;i++) \
57 dst[i] = Sample_##T(src[i*srcstep]); \
61 DECL_TEMPLATE(ALshort
)
62 DECL_TEMPLATE(ALfloat
)
66 static void LoadData(ALfloat
*dst
, const ALvoid
*src
, ALuint srcstep
, enum FmtType srctype
, ALuint samples
)
71 Load_ALbyte(dst
, src
, srcstep
, samples
);
74 Load_ALshort(dst
, src
, srcstep
, samples
);
77 Load_ALfloat(dst
, src
, srcstep
, samples
);
82 static void SilenceData(ALfloat
*dst
, ALuint samples
)
85 for(i
= 0;i
< samples
;i
++)
90 static const ALfloat
*DoFilters(ALfilterState
*lpfilter
, ALfilterState
*hpfilter
,
91 ALfloat
*restrict dst
, const ALfloat
*restrict src
,
92 ALuint numsamples
, enum ActiveFilters type
)
101 ALfilterState_process(lpfilter
, dst
, src
, numsamples
);
104 ALfilterState_process(hpfilter
, dst
, src
, numsamples
);
108 for(i
= 0;i
< numsamples
;)
111 ALuint todo
= minu(64, numsamples
-i
);
113 ALfilterState_process(lpfilter
, temp
, src
+i
, todo
);
114 ALfilterState_process(hpfilter
, dst
+i
, temp
, todo
);
123 ALvoid
MixSource(ALactivesource
*src
, ALCdevice
*Device
, ALuint SamplesToDo
)
125 ALsource
*Source
= src
->Source
;
126 ALbufferlistitem
*BufferListItem
;
127 ALuint DataPosInt
, DataPosFrac
;
130 enum Resampler Resampler
;
138 /* Get source info */
139 State
= Source
->state
;
140 BufferListItem
= Source
->current_buffer
;
141 DataPosInt
= Source
->position
;
142 DataPosFrac
= Source
->position_fraction
;
143 Looping
= Source
->Looping
;
144 increment
= src
->Step
;
145 Resampler
= (increment
==FRACTIONONE
) ? PointResampler
: Source
->Resampler
;
146 NumChannels
= Source
->NumChannels
;
147 SampleSize
= Source
->SampleSize
;
149 /* Get current buffer queue item */
153 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
154 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
155 ALuint SrcBufferSize
, DstBufferSize
;
157 /* Figure out how many buffer samples will be needed */
158 DataSize64
= SamplesToDo
-OutPos
;
159 DataSize64
*= increment
;
160 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
161 DataSize64
>>= FRACTIONBITS
;
162 DataSize64
+= BufferPadding
+BufferPrePadding
;
164 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
166 /* Figure out how many samples we can actually mix from this. */
167 DataSize64
= SrcBufferSize
;
168 DataSize64
-= BufferPadding
+BufferPrePadding
;
169 DataSize64
<<= FRACTIONBITS
;
170 DataSize64
-= DataPosFrac
;
172 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
173 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
175 /* Some mixers like having a multiple of 4, so try to give that unless
176 * this is the last update. */
177 if(OutPos
+DstBufferSize
< SamplesToDo
)
180 for(chan
= 0;chan
< NumChannels
;chan
++)
182 const ALfloat
*ResampledData
;
183 ALfloat
*SrcData
= Device
->SourceData
;
184 ALuint SrcDataSize
= 0;
186 if(Source
->SourceType
== AL_STATIC
)
188 const ALbuffer
*ALBuffer
= BufferListItem
->buffer
;
189 const ALubyte
*Data
= ALBuffer
->data
;
193 /* If current pos is beyond the loop range, do not loop */
194 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
198 if(DataPosInt
>= BufferPrePadding
)
199 pos
= DataPosInt
- BufferPrePadding
;
202 DataSize
= BufferPrePadding
- DataPosInt
;
203 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
205 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
206 SrcDataSize
+= DataSize
;
211 /* Copy what's left to play in the source buffer, and clear the
212 * rest of the temp buffer */
213 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
215 LoadData(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
216 NumChannels
, ALBuffer
->FmtType
, DataSize
);
217 SrcDataSize
+= DataSize
;
219 SilenceData(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
220 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
224 ALuint LoopStart
= ALBuffer
->LoopStart
;
225 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
227 if(DataPosInt
>= LoopStart
)
229 pos
= DataPosInt
-LoopStart
;
230 while(pos
< BufferPrePadding
)
231 pos
+= LoopEnd
-LoopStart
;
232 pos
-= BufferPrePadding
;
235 else if(DataPosInt
>= BufferPrePadding
)
236 pos
= DataPosInt
- BufferPrePadding
;
239 DataSize
= BufferPrePadding
- DataPosInt
;
240 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
242 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
243 SrcDataSize
+= DataSize
;
248 /* Copy what's left of this loop iteration, then copy repeats
249 * of the loop section */
250 DataSize
= LoopEnd
- pos
;
251 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
253 LoadData(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
254 NumChannels
, ALBuffer
->FmtType
, DataSize
);
255 SrcDataSize
+= DataSize
;
257 DataSize
= LoopEnd
-LoopStart
;
258 while(SrcBufferSize
> SrcDataSize
)
260 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
262 LoadData(&SrcData
[SrcDataSize
], &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
263 NumChannels
, ALBuffer
->FmtType
, DataSize
);
264 SrcDataSize
+= DataSize
;
270 /* Crawl the buffer queue to fill in the temp buffer */
271 ALbufferlistitem
*tmpiter
= BufferListItem
;
274 if(DataPosInt
>= BufferPrePadding
)
275 pos
= DataPosInt
- BufferPrePadding
;
278 pos
= BufferPrePadding
- DataPosInt
;
281 ALbufferlistitem
*prev
;
282 if((prev
=tmpiter
->prev
) != NULL
)
287 tmpiter
= tmpiter
->next
;
291 ALuint DataSize
= minu(SrcBufferSize
- SrcDataSize
, pos
);
293 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
294 SrcDataSize
+= DataSize
;
302 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
304 pos
= tmpiter
->buffer
->SampleLen
- pos
;
307 pos
-= tmpiter
->buffer
->SampleLen
;
312 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
314 const ALbuffer
*ALBuffer
;
315 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
317 const ALubyte
*Data
= ALBuffer
->data
;
318 ALuint DataSize
= ALBuffer
->SampleLen
;
320 /* Skip the data already played */
325 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
329 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
330 LoadData(&SrcData
[SrcDataSize
], Data
, NumChannels
,
331 ALBuffer
->FmtType
, DataSize
);
332 SrcDataSize
+= DataSize
;
335 tmpiter
= tmpiter
->next
;
336 if(!tmpiter
&& Looping
)
337 tmpiter
= Source
->queue
;
340 SilenceData(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
341 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
346 /* Now resample, then filter and mix to the appropriate outputs. */
347 ResampledData
= src
->Resample(
348 &SrcData
[BufferPrePadding
], DataPosFrac
, increment
,
349 Device
->ResampledData
, DstBufferSize
352 DirectParams
*parms
= &src
->Direct
;
353 const ALfloat
*samples
;
356 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
357 Device
->FilteredData
, ResampledData
, DstBufferSize
,
358 parms
->Filters
[chan
].ActiveType
361 src
->Mix(samples
, MaxChannels
, parms
->OutBuffer
, parms
->Mix
.Gains
[chan
],
362 parms
->Counter
, OutPos
, DstBufferSize
);
365 parms
->OutBuffer
, samples
, parms
->Counter
, src
->Offset
,
366 OutPos
, parms
->Mix
.Hrtf
.IrSize
, &parms
->Mix
.Hrtf
.Params
[chan
],
367 &parms
->Mix
.Hrtf
.State
[chan
], DstBufferSize
371 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
373 SendParams
*parms
= &src
->Send
[j
];
374 const ALfloat
*samples
;
376 if(!parms
->OutBuffer
)
380 &parms
->Filters
[chan
].LowPass
, &parms
->Filters
[chan
].HighPass
,
381 Device
->FilteredData
, ResampledData
, DstBufferSize
,
382 parms
->Filters
[chan
].ActiveType
384 src
->Mix(samples
, 1, parms
->OutBuffer
, &parms
->Gain
,
385 parms
->Counter
, OutPos
, DstBufferSize
);
388 /* Update positions */
389 DataPosFrac
+= increment
*DstBufferSize
;
390 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
391 DataPosFrac
&= FRACTIONMASK
;
393 OutPos
+= DstBufferSize
;
394 src
->Offset
+= DstBufferSize
;
395 src
->Direct
.Counter
= maxu(src
->Direct
.Counter
, DstBufferSize
) - DstBufferSize
;
396 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
397 src
->Send
[j
].Counter
= maxu(src
->Send
[j
].Counter
, DstBufferSize
) - DstBufferSize
;
399 /* Handle looping sources */
402 const ALbuffer
*ALBuffer
;
404 ALuint LoopStart
= 0;
407 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
409 DataSize
= ALBuffer
->SampleLen
;
410 LoopStart
= ALBuffer
->LoopStart
;
411 LoopEnd
= ALBuffer
->LoopEnd
;
412 if(LoopEnd
> DataPosInt
)
416 if(Looping
&& Source
->SourceType
== AL_STATIC
)
418 assert(LoopEnd
> LoopStart
);
419 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
423 if(DataSize
> DataPosInt
)
426 if(BufferListItem
->next
)
427 BufferListItem
= BufferListItem
->next
;
429 BufferListItem
= Source
->queue
;
433 BufferListItem
= NULL
;
439 DataPosInt
-= DataSize
;
441 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
443 /* Update source info */
444 Source
->state
= State
;
445 Source
->current_buffer
= BufferListItem
;
446 Source
->position
= DataPosInt
;
447 Source
->position_fraction
= DataPosFrac
;