Move atomic method definitions to a separate common source
[openal-soft.git] / Alc / mixer.c
blob6947e6e4760f48487b78df9eb3c29b83467abeb5
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 DoFilter(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src,
88 ALuint numsamples)
90 ALuint i;
91 for(i = 0;i < numsamples;i++)
92 dst[i] = ALfilterState_processSingle(filter, src[i]);
96 ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
98 ALsource *Source = src->Source;
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 = src->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 samples will be needed */
135 DataSize64 = SamplesToDo-OutPos;
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 -= DataPosFrac;
149 DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
150 DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
152 /* Some mixers like having a multiple of 4, so try to give that unless
153 * this is the last update. */
154 if(OutPos+DstBufferSize < SamplesToDo)
155 DstBufferSize &= ~3;
157 for(chan = 0;chan < NumChannels;chan++)
159 ALfloat *SrcData = Device->SampleData1;
160 ALfloat *ResampledData = Device->SampleData2;
161 ALuint SrcDataSize = 0;
163 if(Source->SourceType == AL_STATIC)
165 const ALbuffer *ALBuffer = Source->queue->buffer;
166 const ALubyte *Data = ALBuffer->data;
167 ALuint DataSize;
168 ALuint pos;
170 /* If current pos is beyond the loop range, do not loop */
171 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
173 Looping = AL_FALSE;
175 if(DataPosInt >= BufferPrePadding)
176 pos = DataPosInt - BufferPrePadding;
177 else
179 DataSize = BufferPrePadding - DataPosInt;
180 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
182 SilenceData(&SrcData[SrcDataSize], DataSize);
183 SrcDataSize += DataSize;
185 pos = 0;
188 /* Copy what's left to play in the source buffer, and clear the
189 * rest of the temp buffer */
190 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
192 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
193 NumChannels, ALBuffer->FmtType, DataSize);
194 SrcDataSize += DataSize;
196 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
197 SrcDataSize += SrcBufferSize - SrcDataSize;
199 else
201 ALuint LoopStart = ALBuffer->LoopStart;
202 ALuint LoopEnd = ALBuffer->LoopEnd;
204 if(DataPosInt >= LoopStart)
206 pos = DataPosInt-LoopStart;
207 while(pos < BufferPrePadding)
208 pos += LoopEnd-LoopStart;
209 pos -= BufferPrePadding;
210 pos += LoopStart;
212 else if(DataPosInt >= BufferPrePadding)
213 pos = DataPosInt - BufferPrePadding;
214 else
216 DataSize = BufferPrePadding - DataPosInt;
217 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
219 SilenceData(&SrcData[SrcDataSize], DataSize);
220 SrcDataSize += DataSize;
222 pos = 0;
225 /* Copy what's left of this loop iteration, then copy repeats
226 * of the loop section */
227 DataSize = LoopEnd - pos;
228 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
230 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
231 NumChannels, ALBuffer->FmtType, DataSize);
232 SrcDataSize += DataSize;
234 DataSize = LoopEnd-LoopStart;
235 while(SrcBufferSize > SrcDataSize)
237 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
239 LoadData(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
240 NumChannels, ALBuffer->FmtType, DataSize);
241 SrcDataSize += DataSize;
245 else
247 /* Crawl the buffer queue to fill in the temp buffer */
248 ALbufferlistitem *tmpiter = BufferListItem;
249 ALuint pos;
251 if(DataPosInt >= BufferPrePadding)
252 pos = DataPosInt - BufferPrePadding;
253 else
255 pos = BufferPrePadding - DataPosInt;
256 while(pos > 0)
258 if(!tmpiter->prev && !Looping)
260 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
262 SilenceData(&SrcData[SrcDataSize], DataSize);
263 SrcDataSize += DataSize;
265 pos = 0;
266 break;
269 if(tmpiter->prev)
270 tmpiter = tmpiter->prev;
271 else
273 while(tmpiter->next)
274 tmpiter = tmpiter->next;
277 if(tmpiter->buffer)
279 if((ALuint)tmpiter->buffer->SampleLen > pos)
281 pos = tmpiter->buffer->SampleLen - pos;
282 break;
284 pos -= tmpiter->buffer->SampleLen;
289 while(tmpiter && SrcBufferSize > SrcDataSize)
291 const ALbuffer *ALBuffer;
292 if((ALBuffer=tmpiter->buffer) != NULL)
294 const ALubyte *Data = ALBuffer->data;
295 ALuint DataSize = ALBuffer->SampleLen;
297 /* Skip the data already played */
298 if(DataSize <= pos)
299 pos -= DataSize;
300 else
302 Data += (pos*NumChannels + chan)*SampleSize;
303 DataSize -= pos;
304 pos -= pos;
306 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
307 LoadData(&SrcData[SrcDataSize], Data, NumChannels,
308 ALBuffer->FmtType, DataSize);
309 SrcDataSize += DataSize;
312 tmpiter = tmpiter->next;
313 if(!tmpiter && Looping)
314 tmpiter = Source->queue;
315 else if(!tmpiter)
317 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
318 SrcDataSize += SrcBufferSize - SrcDataSize;
323 /* Now resample, then filter and mix to the appropriate outputs. */
324 src->Resample(&SrcData[BufferPrePadding], DataPosFrac,
325 increment, ResampledData, DstBufferSize);
328 DirectParams *directparms = &src->Direct;
330 DoFilter(&directparms->LpFilter[chan], SrcData, ResampledData,
331 DstBufferSize);
332 src->DryMix(directparms, SrcData, chan, OutPos, DstBufferSize);
335 for(j = 0;j < Device->NumAuxSends;j++)
337 SendParams *sendparms = &src->Send[j];
338 if(!sendparms->OutBuffer)
339 continue;
341 DoFilter(&sendparms->LpFilter[chan], SrcData, ResampledData,
342 DstBufferSize);
343 src->WetMix(sendparms, SrcData, OutPos, DstBufferSize);
346 /* Update positions */
347 for(j = 0;j < DstBufferSize;j++)
349 DataPosFrac += increment;
350 DataPosInt += DataPosFrac>>FRACTIONBITS;
351 DataPosFrac &= FRACTIONMASK;
353 OutPos += DstBufferSize;
355 /* Handle looping sources */
356 while(1)
358 const ALbuffer *ALBuffer;
359 ALuint DataSize = 0;
360 ALuint LoopStart = 0;
361 ALuint LoopEnd = 0;
363 if((ALBuffer=BufferListItem->buffer) != NULL)
365 DataSize = ALBuffer->SampleLen;
366 LoopStart = ALBuffer->LoopStart;
367 LoopEnd = ALBuffer->LoopEnd;
368 if(LoopEnd > DataPosInt)
369 break;
372 if(Looping && Source->SourceType == AL_STATIC)
374 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
375 break;
378 if(DataSize > DataPosInt)
379 break;
381 if(BufferListItem->next)
383 BufferListItem = BufferListItem->next;
384 BuffersPlayed++;
386 else if(Looping)
388 BufferListItem = Source->queue;
389 BuffersPlayed = 0;
391 else
393 State = AL_STOPPED;
394 BufferListItem = Source->queue;
395 BuffersPlayed = Source->BuffersInQueue;
396 DataPosInt = 0;
397 DataPosFrac = 0;
398 break;
401 DataPosInt -= DataSize;
403 } while(State == AL_PLAYING && OutPos < SamplesToDo);
405 /* Update source info */
406 Source->state = State;
407 Source->BuffersPlayed = BuffersPlayed;
408 Source->position = DataPosInt;
409 Source->position_fraction = DataPosFrac;
410 src->Direct.Offset += OutPos;
411 src->Direct.Counter = maxu(src->Direct.Counter, OutPos) - OutPos;