Use WARN when implicitly deleting resources with the context
[openal-soft.git] / Alc / mixer.c
blobf75a7803cd661e0f2a5744fa1555bee1d144d989
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 LoadData(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 SilenceData(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 = (increment==FRACTIONONE) ? PointResampler : 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 ALfloat *SrcData = Device->SampleData1;
161 ALfloat *ResampledData = Device->SampleData2;
162 ALuint SrcDataSize = 0;
164 if(Source->SourceType == AL_STATIC)
166 const ALbuffer *ALBuffer = Source->queue->buffer;
167 const ALubyte *Data = ALBuffer->data;
168 ALuint DataSize;
169 ALuint pos;
171 /* If current pos is beyond the loop range, do not loop */
172 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
174 Looping = AL_FALSE;
176 if(DataPosInt >= BufferPrePadding)
177 pos = DataPosInt - BufferPrePadding;
178 else
180 DataSize = BufferPrePadding - DataPosInt;
181 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
183 SilenceData(&SrcData[SrcDataSize], DataSize);
184 SrcDataSize += DataSize;
186 pos = 0;
189 /* Copy what's left to play in the source buffer, and clear the
190 * rest of the temp buffer */
191 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
193 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
194 NumChannels, ALBuffer->FmtType, DataSize);
195 SrcDataSize += DataSize;
197 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
198 SrcDataSize += SrcBufferSize - SrcDataSize;
200 else
202 ALuint LoopStart = ALBuffer->LoopStart;
203 ALuint LoopEnd = ALBuffer->LoopEnd;
205 if(DataPosInt >= LoopStart)
207 pos = DataPosInt-LoopStart;
208 while(pos < BufferPrePadding)
209 pos += LoopEnd-LoopStart;
210 pos -= BufferPrePadding;
211 pos += LoopStart;
213 else if(DataPosInt >= BufferPrePadding)
214 pos = DataPosInt - BufferPrePadding;
215 else
217 DataSize = BufferPrePadding - DataPosInt;
218 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
220 SilenceData(&SrcData[SrcDataSize], DataSize);
221 SrcDataSize += DataSize;
223 pos = 0;
226 /* Copy what's left of this loop iteration, then copy repeats
227 * of the loop section */
228 DataSize = LoopEnd - pos;
229 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
231 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
232 NumChannels, ALBuffer->FmtType, DataSize);
233 SrcDataSize += DataSize;
235 DataSize = LoopEnd-LoopStart;
236 while(SrcBufferSize > SrcDataSize)
238 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
240 LoadData(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
241 NumChannels, ALBuffer->FmtType, DataSize);
242 SrcDataSize += DataSize;
246 else
248 /* Crawl the buffer queue to fill in the temp buffer */
249 ALbufferlistitem *tmpiter = BufferListItem;
250 ALuint pos;
252 if(DataPosInt >= BufferPrePadding)
253 pos = DataPosInt - BufferPrePadding;
254 else
256 pos = BufferPrePadding - DataPosInt;
257 while(pos > 0)
259 if(!tmpiter->prev && !Looping)
261 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
263 SilenceData(&SrcData[SrcDataSize], DataSize);
264 SrcDataSize += DataSize;
266 pos = 0;
267 break;
270 if(tmpiter->prev)
271 tmpiter = tmpiter->prev;
272 else
274 while(tmpiter->next)
275 tmpiter = tmpiter->next;
278 if(tmpiter->buffer)
280 if((ALuint)tmpiter->buffer->SampleLen > pos)
282 pos = tmpiter->buffer->SampleLen - pos;
283 break;
285 pos -= tmpiter->buffer->SampleLen;
290 while(tmpiter && SrcBufferSize > SrcDataSize)
292 const ALbuffer *ALBuffer;
293 if((ALBuffer=tmpiter->buffer) != NULL)
295 const ALubyte *Data = ALBuffer->data;
296 ALuint DataSize = ALBuffer->SampleLen;
298 /* Skip the data already played */
299 if(DataSize <= pos)
300 pos -= DataSize;
301 else
303 Data += (pos*NumChannels + chan)*SampleSize;
304 DataSize -= pos;
305 pos -= pos;
307 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
308 LoadData(&SrcData[SrcDataSize], Data, NumChannels,
309 ALBuffer->FmtType, DataSize);
310 SrcDataSize += DataSize;
313 tmpiter = tmpiter->next;
314 if(!tmpiter && Looping)
315 tmpiter = Source->queue;
316 else if(!tmpiter)
318 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
319 SrcDataSize += SrcBufferSize - SrcDataSize;
324 /* Now resample, then filter and mix to the appropriate outputs. */
325 Source->Params.Resample(&SrcData[BufferPrePadding], DataPosFrac,
326 increment, ResampledData, DstBufferSize);
329 DirectParams *directparms = &Source->Params.Direct;
331 Filter2P(&directparms->iirFilter, chan, SrcData, ResampledData,
332 DstBufferSize);
333 Source->Params.DryMix(directparms, SrcData, chan, OutPos,
334 SamplesToDo, DstBufferSize);
337 for(j = 0;j < Device->NumAuxSends;j++)
339 SendParams *sendparms = &Source->Params.Send[j];
340 if(!sendparms->Slot)
341 continue;
343 Filter2P(&sendparms->iirFilter, chan, SrcData, ResampledData,
344 DstBufferSize);
345 Source->Params.WetMix(sendparms, SrcData, OutPos,
346 SamplesToDo, DstBufferSize);
349 /* Update positions */
350 for(j = 0;j < DstBufferSize;j++)
352 DataPosFrac += increment;
353 DataPosInt += DataPosFrac>>FRACTIONBITS;
354 DataPosFrac &= FRACTIONMASK;
356 OutPos += DstBufferSize;
358 /* Handle looping sources */
359 while(1)
361 const ALbuffer *ALBuffer;
362 ALuint DataSize = 0;
363 ALuint LoopStart = 0;
364 ALuint LoopEnd = 0;
366 if((ALBuffer=BufferListItem->buffer) != NULL)
368 DataSize = ALBuffer->SampleLen;
369 LoopStart = ALBuffer->LoopStart;
370 LoopEnd = ALBuffer->LoopEnd;
371 if(LoopEnd > DataPosInt)
372 break;
375 if(Looping && Source->SourceType == AL_STATIC)
377 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
378 break;
381 if(DataSize > DataPosInt)
382 break;
384 if(BufferListItem->next)
386 BufferListItem = BufferListItem->next;
387 BuffersPlayed++;
389 else if(Looping)
391 BufferListItem = Source->queue;
392 BuffersPlayed = 0;
394 else
396 State = AL_STOPPED;
397 BufferListItem = Source->queue;
398 BuffersPlayed = Source->BuffersInQueue;
399 DataPosInt = 0;
400 DataPosFrac = 0;
401 break;
404 DataPosInt -= DataSize;
406 } while(State == AL_PLAYING && OutPos < SamplesToDo);
408 /* Update source info */
409 Source->state = State;
410 Source->BuffersPlayed = BuffersPlayed;
411 Source->position = DataPosInt;
412 Source->position_fraction = DataPosFrac;
413 Source->Hrtf.Offset += OutPos;
414 if(State == AL_PLAYING)
415 Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos;
416 else
418 Source->Hrtf.Counter = 0;
419 Source->Hrtf.Moving = AL_FALSE;