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 srcstep, ALuint samples)\
53 for(i = 0;i < samples;i++) \
54 dst[i] = Sample_##T(src[i*srcstep]); \
58 DECL_TEMPLATE(ALshort
)
59 DECL_TEMPLATE(ALfloat
)
63 static void LoadStack(ALfloat
*dst
, const ALvoid
*src
, ALuint srcstep
, enum FmtType srctype
, ALuint samples
)
68 Load_ALbyte(dst
, src
, srcstep
, samples
);
71 Load_ALshort(dst
, src
, srcstep
, samples
);
74 Load_ALfloat(dst
, src
, srcstep
, samples
);
79 static void SilenceStack(ALfloat
*dst
, ALuint samples
)
82 for(i
= 0;i
< samples
;i
++)
87 static void Filter2P(FILTER
*filter
, ALuint chan
, ALfloat
*RESTRICT dst
,
88 const ALfloat
*RESTRICT src
, ALuint numsamples
)
91 for(i
= 0;i
< numsamples
;i
++)
92 dst
[i
] = lpFilter2P(filter
, chan
, src
[i
]);
93 dst
[i
] = lpFilter2PC(filter
, chan
, src
[i
]);
97 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
99 ALbufferlistitem
*BufferListItem
;
100 ALuint DataPosInt
, DataPosFrac
;
101 ALuint BuffersPlayed
;
104 enum Resampler Resampler
;
112 /* Get source info */
113 State
= Source
->state
;
114 BuffersPlayed
= Source
->BuffersPlayed
;
115 DataPosInt
= Source
->position
;
116 DataPosFrac
= Source
->position_fraction
;
117 Looping
= Source
->Looping
;
118 increment
= Source
->Params
.Step
;
119 Resampler
= Source
->Resampler
;
120 NumChannels
= Source
->NumChannels
;
121 SampleSize
= Source
->SampleSize
;
123 /* Get current buffer queue item */
124 BufferListItem
= Source
->queue
;
125 for(j
= 0;j
< BuffersPlayed
;j
++)
126 BufferListItem
= BufferListItem
->next
;
130 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
131 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
132 ALuint SrcBufferSize
, DstBufferSize
;
134 /* Figure out how many buffer bytes will be needed */
135 DataSize64
= SamplesToDo
-OutPos
+1;
136 DataSize64
*= increment
;
137 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
138 DataSize64
>>= FRACTIONBITS
;
139 DataSize64
+= BufferPadding
+BufferPrePadding
;
141 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
143 /* Figure out how many samples we can actually mix from this. */
144 DataSize64
= SrcBufferSize
;
145 DataSize64
-= BufferPadding
+BufferPrePadding
;
146 DataSize64
<<= FRACTIONBITS
;
147 DataSize64
-= increment
;
148 DataSize64
-= DataPosFrac
;
150 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
151 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
153 /* Some mixers like having a multiple of 4, so try to give that unless
154 * this is the last update. */
155 if(OutPos
+DstBufferSize
< SamplesToDo
)
158 for(chan
= 0;chan
< NumChannels
;chan
++)
160 /* +1 for the predictive sample. */
161 ALIGN(16) ALfloat SrcData
[BUFFERSIZE
+1];
162 ALIGN(16) ALfloat ResampledData
[BUFFERSIZE
+1];
163 ALuint SrcDataSize
= 0;
165 if(Source
->SourceType
== AL_STATIC
)
167 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
168 const ALubyte
*Data
= ALBuffer
->data
;
172 /* If current pos is beyond the loop range, do not loop */
173 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
177 if(DataPosInt
>= BufferPrePadding
)
178 pos
= DataPosInt
- BufferPrePadding
;
181 DataSize
= BufferPrePadding
- DataPosInt
;
182 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
184 SilenceStack(&SrcData
[SrcDataSize
], DataSize
);
185 SrcDataSize
+= DataSize
;
190 /* Copy what's left to play in the source buffer, and clear the
191 * rest of the temp buffer */
192 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
194 LoadStack(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
195 NumChannels
, ALBuffer
->FmtType
, DataSize
);
196 SrcDataSize
+= DataSize
;
198 SilenceStack(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
199 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
203 ALuint LoopStart
= ALBuffer
->LoopStart
;
204 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
206 if(DataPosInt
>= LoopStart
)
208 pos
= DataPosInt
-LoopStart
;
209 while(pos
< BufferPrePadding
)
210 pos
+= LoopEnd
-LoopStart
;
211 pos
-= BufferPrePadding
;
214 else if(DataPosInt
>= BufferPrePadding
)
215 pos
= DataPosInt
- BufferPrePadding
;
218 DataSize
= BufferPrePadding
- DataPosInt
;
219 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
221 SilenceStack(&SrcData
[SrcDataSize
], DataSize
);
222 SrcDataSize
+= DataSize
;
227 /* Copy what's left of this loop iteration, then copy repeats
228 * of the loop section */
229 DataSize
= LoopEnd
- pos
;
230 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
232 LoadStack(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
233 NumChannels
, ALBuffer
->FmtType
, DataSize
);
234 SrcDataSize
+= DataSize
;
236 DataSize
= LoopEnd
-LoopStart
;
237 while(SrcBufferSize
> SrcDataSize
)
239 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
241 LoadStack(&SrcData
[SrcDataSize
], &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
242 NumChannels
, ALBuffer
->FmtType
, DataSize
);
243 SrcDataSize
+= DataSize
;
249 /* Crawl the buffer queue to fill in the temp buffer */
250 ALbufferlistitem
*tmpiter
= BufferListItem
;
253 if(DataPosInt
>= BufferPrePadding
)
254 pos
= DataPosInt
- BufferPrePadding
;
257 pos
= BufferPrePadding
- DataPosInt
;
260 if(!tmpiter
->prev
&& !Looping
)
262 ALuint DataSize
= minu(SrcBufferSize
- SrcDataSize
, pos
);
264 SilenceStack(&SrcData
[SrcDataSize
], DataSize
);
265 SrcDataSize
+= DataSize
;
272 tmpiter
= tmpiter
->prev
;
276 tmpiter
= tmpiter
->next
;
281 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
283 pos
= tmpiter
->buffer
->SampleLen
- pos
;
286 pos
-= tmpiter
->buffer
->SampleLen
;
291 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
293 const ALbuffer
*ALBuffer
;
294 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
296 const ALubyte
*Data
= ALBuffer
->data
;
297 ALuint DataSize
= ALBuffer
->SampleLen
;
299 /* Skip the data already played */
304 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
308 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
309 LoadStack(&SrcData
[SrcDataSize
], Data
, NumChannels
,
310 ALBuffer
->FmtType
, DataSize
);
311 SrcDataSize
+= DataSize
;
314 tmpiter
= tmpiter
->next
;
315 if(!tmpiter
&& Looping
)
316 tmpiter
= Source
->queue
;
319 SilenceStack(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
320 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
325 /* Now resample, then filter and mix to the appropriate outputs. */
326 Source
->Params
.Resample(&SrcData
[BufferPrePadding
], DataPosFrac
,
327 increment
, ResampledData
, DstBufferSize
);
330 DirectParams
*directparms
= &Source
->Params
.Direct
;
332 Filter2P(&directparms
->iirFilter
, chan
, SrcData
, ResampledData
,
334 Source
->Params
.DryMix(Source
, Device
, directparms
, SrcData
,
335 chan
, OutPos
, SamplesToDo
, DstBufferSize
);
338 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
340 SendParams
*sendparms
= &Source
->Params
.Send
[j
];
344 Filter2P(&sendparms
->iirFilter
, chan
, SrcData
, ResampledData
,
346 Source
->Params
.WetMix(sendparms
, SrcData
, OutPos
,
347 SamplesToDo
, DstBufferSize
);
350 /* Update positions */
351 for(j
= 0;j
< DstBufferSize
;j
++)
353 DataPosFrac
+= increment
;
354 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
355 DataPosFrac
&= FRACTIONMASK
;
357 OutPos
+= DstBufferSize
;
359 /* Handle looping sources */
362 const ALbuffer
*ALBuffer
;
364 ALuint LoopStart
= 0;
367 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
369 DataSize
= ALBuffer
->SampleLen
;
370 LoopStart
= ALBuffer
->LoopStart
;
371 LoopEnd
= ALBuffer
->LoopEnd
;
372 if(LoopEnd
> DataPosInt
)
376 if(Looping
&& Source
->SourceType
== AL_STATIC
)
378 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
382 if(DataSize
> DataPosInt
)
385 if(BufferListItem
->next
)
387 BufferListItem
= BufferListItem
->next
;
392 BufferListItem
= Source
->queue
;
398 BufferListItem
= Source
->queue
;
399 BuffersPlayed
= Source
->BuffersInQueue
;
405 DataPosInt
-= DataSize
;
407 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
409 /* Update source info */
410 Source
->state
= State
;
411 Source
->BuffersPlayed
= BuffersPlayed
;
412 Source
->position
= DataPosInt
;
413 Source
->position_fraction
= DataPosFrac
;
414 Source
->Hrtf
.Offset
+= OutPos
;
415 if(State
== AL_PLAYING
)
417 Source
->Hrtf
.Counter
= maxu(Source
->Hrtf
.Counter
, OutPos
) - OutPos
;
418 Source
->Hrtf
.Moving
= AL_TRUE
;
422 Source
->Hrtf
.Counter
= 0;
423 Source
->Hrtf
.Moving
= AL_FALSE
;