Fix potential buffer overflow with temp sample space
[openal-soft.git] / Alc / mixer.c
blob7671f1b332125307fae2a25a2a12cdfc9b5d56ed
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.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)
47 { return val; }
49 #define DECL_TEMPLATE(T) \
50 static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
51 { \
52 ALuint i; \
53 for(i = 0;i < samples;i++) \
54 dst[i] = Sample_##T(src[i*srcstep]); \
57 DECL_TEMPLATE(ALbyte)
58 DECL_TEMPLATE(ALshort)
59 DECL_TEMPLATE(ALfloat)
61 #undef DECL_TEMPLATE
63 static void LoadStack(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
65 switch(srctype)
67 case FmtByte:
68 Load_ALbyte(dst, src, srcstep, samples);
69 break;
70 case FmtShort:
71 Load_ALshort(dst, src, srcstep, samples);
72 break;
73 case FmtFloat:
74 Load_ALfloat(dst, src, srcstep, samples);
75 break;
79 static void SilenceStack(ALfloat *dst, ALuint samples)
81 ALuint i;
82 for(i = 0;i < samples;i++)
83 dst[i] = 0.0f;
87 static void Filter2P(FILTER *filter, ALuint chan, ALfloat *RESTRICT dst,
88 const ALfloat *RESTRICT src, ALuint numsamples)
90 ALuint i;
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;
102 ALboolean Looping;
103 ALuint increment;
104 enum Resampler Resampler;
105 ALenum State;
106 ALuint OutPos;
107 ALuint NumChannels;
108 ALuint SampleSize;
109 ALint64 DataSize64;
110 ALuint chan, j;
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;
128 OutPos = 0;
129 do {
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)
156 DstBufferSize &= ~3;
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;
169 ALuint DataSize;
170 ALuint pos;
172 /* If current pos is beyond the loop range, do not loop */
173 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
175 Looping = AL_FALSE;
177 if(DataPosInt >= BufferPrePadding)
178 pos = DataPosInt - BufferPrePadding;
179 else
181 DataSize = BufferPrePadding - DataPosInt;
182 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
184 SilenceStack(&SrcData[SrcDataSize], DataSize);
185 SrcDataSize += DataSize;
187 pos = 0;
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;
201 else
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;
212 pos += LoopStart;
214 else if(DataPosInt >= BufferPrePadding)
215 pos = DataPosInt - BufferPrePadding;
216 else
218 DataSize = BufferPrePadding - DataPosInt;
219 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
221 SilenceStack(&SrcData[SrcDataSize], DataSize);
222 SrcDataSize += DataSize;
224 pos = 0;
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;
247 else
249 /* Crawl the buffer queue to fill in the temp buffer */
250 ALbufferlistitem *tmpiter = BufferListItem;
251 ALuint pos;
253 if(DataPosInt >= BufferPrePadding)
254 pos = DataPosInt - BufferPrePadding;
255 else
257 pos = BufferPrePadding - DataPosInt;
258 while(pos > 0)
260 if(!tmpiter->prev && !Looping)
262 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
264 SilenceStack(&SrcData[SrcDataSize], DataSize);
265 SrcDataSize += DataSize;
267 pos = 0;
268 break;
271 if(tmpiter->prev)
272 tmpiter = tmpiter->prev;
273 else
275 while(tmpiter->next)
276 tmpiter = tmpiter->next;
279 if(tmpiter->buffer)
281 if((ALuint)tmpiter->buffer->SampleLen > pos)
283 pos = tmpiter->buffer->SampleLen - pos;
284 break;
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 */
300 if(DataSize <= pos)
301 pos -= DataSize;
302 else
304 Data += (pos*NumChannels + chan)*SampleSize;
305 DataSize -= pos;
306 pos -= pos;
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;
317 else if(!tmpiter)
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,
333 DstBufferSize);
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];
341 if(!sendparms->Slot)
342 continue;
344 Filter2P(&sendparms->iirFilter, chan, SrcData, ResampledData,
345 DstBufferSize);
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 */
360 while(1)
362 const ALbuffer *ALBuffer;
363 ALuint DataSize = 0;
364 ALuint LoopStart = 0;
365 ALuint LoopEnd = 0;
367 if((ALBuffer=BufferListItem->buffer) != NULL)
369 DataSize = ALBuffer->SampleLen;
370 LoopStart = ALBuffer->LoopStart;
371 LoopEnd = ALBuffer->LoopEnd;
372 if(LoopEnd > DataPosInt)
373 break;
376 if(Looping && Source->SourceType == AL_STATIC)
378 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
379 break;
382 if(DataSize > DataPosInt)
383 break;
385 if(BufferListItem->next)
387 BufferListItem = BufferListItem->next;
388 BuffersPlayed++;
390 else if(Looping)
392 BufferListItem = Source->queue;
393 BuffersPlayed = 0;
395 else
397 State = AL_STOPPED;
398 BufferListItem = Source->queue;
399 BuffersPlayed = Source->BuffersInQueue;
400 DataPosInt = 0;
401 DataPosFrac = 0;
402 break;
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;
420 else
422 Source->Hrtf.Counter = 0;
423 Source->Hrtf.Moving = AL_FALSE;