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 LoadData(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 SilenceData(ALfloat
*dst
, ALuint samples
)
82 for(i
= 0;i
< samples
;i
++)
87 static void DoFilters(ALfilterState
*lpfilter
, ALfloat
*restrict dst
, const ALfloat
*restrict src
,
88 ALuint numsamples
, enum ActiveFilters type
)
94 memcpy(dst
, src
, numsamples
* sizeof(ALfloat
));
98 for(i
= 0;i
< numsamples
;i
++)
99 dst
[i
] = ALfilterState_processSingle(lpfilter
, src
[i
]);
105 ALvoid
MixSource(ALactivesource
*src
, ALCdevice
*Device
, ALuint SamplesToDo
)
107 ALsource
*Source
= src
->Source
;
108 ALbufferlistitem
*BufferListItem
;
109 ALuint DataPosInt
, DataPosFrac
;
112 enum Resampler Resampler
;
120 /* Get source info */
121 State
= Source
->state
;
122 BufferListItem
= Source
->current_buffer
;
123 DataPosInt
= Source
->position
;
124 DataPosFrac
= Source
->position_fraction
;
125 Looping
= Source
->Looping
;
126 increment
= src
->Step
;
127 Resampler
= (increment
==FRACTIONONE
) ? PointResampler
: Source
->Resampler
;
128 NumChannels
= Source
->NumChannels
;
129 SampleSize
= Source
->SampleSize
;
131 /* Get current buffer queue item */
135 const ALuint BufferPrePadding
= ResamplerPrePadding
[Resampler
];
136 const ALuint BufferPadding
= ResamplerPadding
[Resampler
];
137 ALuint SrcBufferSize
, DstBufferSize
;
139 /* Figure out how many buffer samples will be needed */
140 DataSize64
= SamplesToDo
-OutPos
;
141 DataSize64
*= increment
;
142 DataSize64
+= DataPosFrac
+FRACTIONMASK
;
143 DataSize64
>>= FRACTIONBITS
;
144 DataSize64
+= BufferPadding
+BufferPrePadding
;
146 SrcBufferSize
= (ALuint
)mini64(DataSize64
, BUFFERSIZE
);
148 /* Figure out how many samples we can actually mix from this. */
149 DataSize64
= SrcBufferSize
;
150 DataSize64
-= BufferPadding
+BufferPrePadding
;
151 DataSize64
<<= FRACTIONBITS
;
152 DataSize64
-= DataPosFrac
;
154 DstBufferSize
= (ALuint
)((DataSize64
+(increment
-1)) / increment
);
155 DstBufferSize
= minu(DstBufferSize
, (SamplesToDo
-OutPos
));
157 /* Some mixers like having a multiple of 4, so try to give that unless
158 * this is the last update. */
159 if(OutPos
+DstBufferSize
< SamplesToDo
)
162 for(chan
= 0;chan
< NumChannels
;chan
++)
164 ALfloat
*SrcData
= Device
->SampleData1
;
165 ALfloat
*ResampledData
= Device
->SampleData2
;
166 ALuint SrcDataSize
= 0;
168 if(Source
->SourceType
== AL_STATIC
)
170 const ALbuffer
*ALBuffer
= Source
->queue
->buffer
;
171 const ALubyte
*Data
= ALBuffer
->data
;
175 /* If current pos is beyond the loop range, do not loop */
176 if(Looping
== AL_FALSE
|| DataPosInt
>= (ALuint
)ALBuffer
->LoopEnd
)
180 if(DataPosInt
>= BufferPrePadding
)
181 pos
= DataPosInt
- BufferPrePadding
;
184 DataSize
= BufferPrePadding
- DataPosInt
;
185 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
187 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
188 SrcDataSize
+= DataSize
;
193 /* Copy what's left to play in the source buffer, and clear the
194 * rest of the temp buffer */
195 DataSize
= minu(SrcBufferSize
- SrcDataSize
, ALBuffer
->SampleLen
- pos
);
197 LoadData(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
198 NumChannels
, ALBuffer
->FmtType
, DataSize
);
199 SrcDataSize
+= DataSize
;
201 SilenceData(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
202 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
206 ALuint LoopStart
= ALBuffer
->LoopStart
;
207 ALuint LoopEnd
= ALBuffer
->LoopEnd
;
209 if(DataPosInt
>= LoopStart
)
211 pos
= DataPosInt
-LoopStart
;
212 while(pos
< BufferPrePadding
)
213 pos
+= LoopEnd
-LoopStart
;
214 pos
-= BufferPrePadding
;
217 else if(DataPosInt
>= BufferPrePadding
)
218 pos
= DataPosInt
- BufferPrePadding
;
221 DataSize
= BufferPrePadding
- DataPosInt
;
222 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
224 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
225 SrcDataSize
+= DataSize
;
230 /* Copy what's left of this loop iteration, then copy repeats
231 * of the loop section */
232 DataSize
= LoopEnd
- pos
;
233 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
235 LoadData(&SrcData
[SrcDataSize
], &Data
[(pos
*NumChannels
+ chan
)*SampleSize
],
236 NumChannels
, ALBuffer
->FmtType
, DataSize
);
237 SrcDataSize
+= DataSize
;
239 DataSize
= LoopEnd
-LoopStart
;
240 while(SrcBufferSize
> SrcDataSize
)
242 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
244 LoadData(&SrcData
[SrcDataSize
], &Data
[(LoopStart
*NumChannels
+ chan
)*SampleSize
],
245 NumChannels
, ALBuffer
->FmtType
, DataSize
);
246 SrcDataSize
+= DataSize
;
252 /* Crawl the buffer queue to fill in the temp buffer */
253 ALbufferlistitem
*tmpiter
= BufferListItem
;
256 if(DataPosInt
>= BufferPrePadding
)
257 pos
= DataPosInt
- BufferPrePadding
;
260 pos
= BufferPrePadding
- DataPosInt
;
263 ALbufferlistitem
*prev
;
264 if((prev
=tmpiter
->prev
) != NULL
)
269 tmpiter
= tmpiter
->next
;
273 ALuint DataSize
= minu(SrcBufferSize
- SrcDataSize
, pos
);
275 SilenceData(&SrcData
[SrcDataSize
], DataSize
);
276 SrcDataSize
+= DataSize
;
284 if((ALuint
)tmpiter
->buffer
->SampleLen
> pos
)
286 pos
= tmpiter
->buffer
->SampleLen
- pos
;
289 pos
-= tmpiter
->buffer
->SampleLen
;
294 while(tmpiter
&& SrcBufferSize
> SrcDataSize
)
296 const ALbuffer
*ALBuffer
;
297 if((ALBuffer
=tmpiter
->buffer
) != NULL
)
299 const ALubyte
*Data
= ALBuffer
->data
;
300 ALuint DataSize
= ALBuffer
->SampleLen
;
302 /* Skip the data already played */
307 Data
+= (pos
*NumChannels
+ chan
)*SampleSize
;
311 DataSize
= minu(SrcBufferSize
- SrcDataSize
, DataSize
);
312 LoadData(&SrcData
[SrcDataSize
], Data
, NumChannels
,
313 ALBuffer
->FmtType
, DataSize
);
314 SrcDataSize
+= DataSize
;
317 tmpiter
= tmpiter
->next
;
318 if(!tmpiter
&& Looping
)
319 tmpiter
= Source
->queue
;
322 SilenceData(&SrcData
[SrcDataSize
], SrcBufferSize
- SrcDataSize
);
323 SrcDataSize
+= SrcBufferSize
- SrcDataSize
;
328 /* Now resample, then filter and mix to the appropriate outputs. */
329 src
->Resample(&SrcData
[BufferPrePadding
], DataPosFrac
,
330 increment
, ResampledData
, DstBufferSize
);
333 DirectParams
*directparms
= &src
->Direct
;
335 DoFilters(&directparms
->LpFilter
[chan
], SrcData
, ResampledData
,
336 DstBufferSize
, directparms
->Filters
[chan
]);
337 src
->DryMix(directparms
, SrcData
, chan
, OutPos
, DstBufferSize
);
340 for(j
= 0;j
< Device
->NumAuxSends
;j
++)
342 SendParams
*sendparms
= &src
->Send
[j
];
343 if(!sendparms
->OutBuffer
)
346 DoFilters(&sendparms
->LpFilter
[chan
], SrcData
, ResampledData
,
347 DstBufferSize
, sendparms
->Filters
[chan
]);
348 src
->WetMix(sendparms
, SrcData
, OutPos
, DstBufferSize
);
351 /* Update positions */
352 for(j
= 0;j
< DstBufferSize
;j
++)
354 DataPosFrac
+= increment
;
355 DataPosInt
+= DataPosFrac
>>FRACTIONBITS
;
356 DataPosFrac
&= FRACTIONMASK
;
358 OutPos
+= DstBufferSize
;
360 /* Handle looping sources */
363 const ALbuffer
*ALBuffer
;
365 ALuint LoopStart
= 0;
368 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
370 DataSize
= ALBuffer
->SampleLen
;
371 LoopStart
= ALBuffer
->LoopStart
;
372 LoopEnd
= ALBuffer
->LoopEnd
;
373 if(LoopEnd
> DataPosInt
)
377 if(Looping
&& Source
->SourceType
== AL_STATIC
)
379 assert(LoopEnd
> LoopStart
);
380 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
384 if(DataSize
> DataPosInt
)
387 if(BufferListItem
->next
)
388 BufferListItem
= BufferListItem
->next
;
390 BufferListItem
= Source
->queue
;
394 BufferListItem
= NULL
;
400 DataPosInt
-= DataSize
;
402 } while(State
== AL_PLAYING
&& OutPos
< SamplesToDo
);
404 /* Update source info */
405 Source
->state
= State
;
406 Source
->current_buffer
= BufferListItem
;
407 Source
->position
= DataPosInt
;
408 Source
->position_fraction
= DataPosFrac
;
409 src
->Direct
.Offset
+= OutPos
;
410 src
->Direct
.Counter
= maxu(src
->Direct
.Counter
, OutPos
) - OutPos
;