Add macros for generic atomic functionality
[openal-soft.git] / Alc / mixer.c
blob7141a8aeb3ab1c8422b85a9afcb929fcfbb3d265
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"
38 #include "mixer_defs.h"
41 extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
44 static inline HrtfMixerFunc SelectHrtfMixer(void)
46 #ifdef HAVE_SSE
47 if((CPUCapFlags&CPU_CAP_SSE))
48 return MixHrtf_SSE;
49 #endif
50 #ifdef HAVE_NEON
51 if((CPUCapFlags&CPU_CAP_NEON))
52 return MixHrtf_Neon;
53 #endif
55 return MixHrtf_C;
58 static inline MixerFunc SelectMixer(void)
60 #ifdef HAVE_SSE
61 if((CPUCapFlags&CPU_CAP_SSE))
62 return Mix_SSE;
63 #endif
64 #ifdef HAVE_NEON
65 if((CPUCapFlags&CPU_CAP_NEON))
66 return Mix_Neon;
67 #endif
69 return Mix_C;
72 static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
74 if(increment == FRACTIONONE)
75 return Resample_copy32_C;
76 switch(Resampler)
78 case PointResampler:
79 return Resample_point32_C;
80 case LinearResampler:
81 #ifdef HAVE_SSE4_1
82 if((CPUCapFlags&CPU_CAP_SSE4_1))
83 return Resample_lerp32_SSE41;
84 #endif
85 #ifdef HAVE_SSE2
86 if((CPUCapFlags&CPU_CAP_SSE2))
87 return Resample_lerp32_SSE2;
88 #endif
89 return Resample_lerp32_C;
90 case CubicResampler:
91 return Resample_cubic32_C;
92 case ResamplerMax:
93 /* Shouldn't happen */
94 break;
97 return Resample_point32_C;
101 static inline ALfloat Sample_ALbyte(ALbyte val)
102 { return val * (1.0f/127.0f); }
104 static inline ALfloat Sample_ALshort(ALshort val)
105 { return val * (1.0f/32767.0f); }
107 static inline ALfloat Sample_ALfloat(ALfloat val)
108 { return val; }
110 #define DECL_TEMPLATE(T) \
111 static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
113 ALuint i; \
114 for(i = 0;i < samples;i++) \
115 dst[i] = Sample_##T(src[i*srcstep]); \
118 DECL_TEMPLATE(ALbyte)
119 DECL_TEMPLATE(ALshort)
120 DECL_TEMPLATE(ALfloat)
122 #undef DECL_TEMPLATE
124 static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
126 switch(srctype)
128 case FmtByte:
129 Load_ALbyte(dst, src, srcstep, samples);
130 break;
131 case FmtShort:
132 Load_ALshort(dst, src, srcstep, samples);
133 break;
134 case FmtFloat:
135 Load_ALfloat(dst, src, srcstep, samples);
136 break;
140 static void SilenceSamples(ALfloat *dst, ALuint samples)
142 ALuint i;
143 for(i = 0;i < samples;i++)
144 dst[i] = 0.0f;
148 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
149 ALfloat *restrict dst, const ALfloat *restrict src,
150 ALuint numsamples, enum ActiveFilters type)
152 ALuint i;
153 switch(type)
155 case AF_None:
156 break;
158 case AF_LowPass:
159 ALfilterState_process(lpfilter, dst, src, numsamples);
160 return dst;
161 case AF_HighPass:
162 ALfilterState_process(hpfilter, dst, src, numsamples);
163 return dst;
165 case AF_BandPass:
166 for(i = 0;i < numsamples;)
168 ALfloat temp[64];
169 ALuint todo = minu(64, numsamples-i);
171 ALfilterState_process(lpfilter, temp, src+i, todo);
172 ALfilterState_process(hpfilter, dst+i, temp, todo);
173 i += todo;
175 return dst;
177 return src;
181 ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
183 MixerFunc Mix;
184 HrtfMixerFunc HrtfMix;
185 ResamplerFunc Resample;
186 ALsource *Source = src->Source;
187 ALbufferlistitem *BufferListItem;
188 ALuint DataPosInt, DataPosFrac;
189 ALboolean Looping;
190 ALuint increment;
191 enum Resampler Resampler;
192 ALenum State;
193 ALuint OutPos;
194 ALuint NumChannels;
195 ALuint SampleSize;
196 ALint64 DataSize64;
197 ALuint chan, j;
199 /* Get source info */
200 State = Source->state;
201 BufferListItem = Source->current_buffer;
202 DataPosInt = Source->position;
203 DataPosFrac = Source->position_fraction;
204 Looping = Source->Looping;
205 increment = src->Step;
206 Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
207 NumChannels = Source->NumChannels;
208 SampleSize = Source->SampleSize;
210 Mix = SelectMixer();
211 HrtfMix = SelectHrtfMixer();
212 Resample = SelectResampler(Resampler, increment);
214 OutPos = 0;
215 do {
216 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
217 const ALuint BufferPadding = ResamplerPadding[Resampler];
218 ALuint SrcBufferSize, DstBufferSize;
220 /* Figure out how many buffer samples will be needed */
221 DataSize64 = SamplesToDo-OutPos;
222 DataSize64 *= increment;
223 DataSize64 += DataPosFrac+FRACTIONMASK;
224 DataSize64 >>= FRACTIONBITS;
225 DataSize64 += BufferPadding+BufferPrePadding;
227 SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
229 /* Figure out how many samples we can actually mix from this. */
230 DataSize64 = SrcBufferSize;
231 DataSize64 -= BufferPadding+BufferPrePadding;
232 DataSize64 <<= FRACTIONBITS;
233 DataSize64 -= DataPosFrac;
235 DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
236 DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
238 /* Some mixers like having a multiple of 4, so try to give that unless
239 * this is the last update. */
240 if(OutPos+DstBufferSize < SamplesToDo)
241 DstBufferSize &= ~3;
243 for(chan = 0;chan < NumChannels;chan++)
245 const ALfloat *ResampledData;
246 ALfloat *SrcData = Device->SourceData;
247 ALuint SrcDataSize = 0;
249 if(Source->SourceType == AL_STATIC)
251 const ALbuffer *ALBuffer = BufferListItem->buffer;
252 const ALubyte *Data = ALBuffer->data;
253 ALuint DataSize;
254 ALuint pos;
256 /* If current pos is beyond the loop range, do not loop */
257 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
259 Looping = AL_FALSE;
261 if(DataPosInt >= BufferPrePadding)
262 pos = DataPosInt - BufferPrePadding;
263 else
265 DataSize = BufferPrePadding - DataPosInt;
266 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
268 SilenceSamples(&SrcData[SrcDataSize], DataSize);
269 SrcDataSize += DataSize;
271 pos = 0;
274 /* Copy what's left to play in the source buffer, and clear the
275 * rest of the temp buffer */
276 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
278 LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
279 NumChannels, ALBuffer->FmtType, DataSize);
280 SrcDataSize += DataSize;
282 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
283 SrcDataSize += SrcBufferSize - SrcDataSize;
285 else
287 ALuint LoopStart = ALBuffer->LoopStart;
288 ALuint LoopEnd = ALBuffer->LoopEnd;
290 if(DataPosInt >= LoopStart)
292 pos = DataPosInt-LoopStart;
293 while(pos < BufferPrePadding)
294 pos += LoopEnd-LoopStart;
295 pos -= BufferPrePadding;
296 pos += LoopStart;
298 else if(DataPosInt >= BufferPrePadding)
299 pos = DataPosInt - BufferPrePadding;
300 else
302 DataSize = BufferPrePadding - DataPosInt;
303 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
305 SilenceSamples(&SrcData[SrcDataSize], DataSize);
306 SrcDataSize += DataSize;
308 pos = 0;
311 /* Copy what's left of this loop iteration, then copy repeats
312 * of the loop section */
313 DataSize = LoopEnd - pos;
314 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
316 LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
317 NumChannels, ALBuffer->FmtType, DataSize);
318 SrcDataSize += DataSize;
320 DataSize = LoopEnd-LoopStart;
321 while(SrcBufferSize > SrcDataSize)
323 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
325 LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
326 NumChannels, ALBuffer->FmtType, DataSize);
327 SrcDataSize += DataSize;
331 else
333 /* Crawl the buffer queue to fill in the temp buffer */
334 ALbufferlistitem *tmpiter = BufferListItem;
335 ALuint pos;
337 if(DataPosInt >= BufferPrePadding)
338 pos = DataPosInt - BufferPrePadding;
339 else
341 pos = BufferPrePadding - DataPosInt;
342 while(pos > 0)
344 ALbufferlistitem *prev;
345 if((prev=tmpiter->prev) != NULL)
346 tmpiter = prev;
347 else if(Looping)
349 while(tmpiter->next)
350 tmpiter = tmpiter->next;
352 else
354 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
356 SilenceSamples(&SrcData[SrcDataSize], DataSize);
357 SrcDataSize += DataSize;
359 pos = 0;
360 break;
363 if(tmpiter->buffer)
365 if((ALuint)tmpiter->buffer->SampleLen > pos)
367 pos = tmpiter->buffer->SampleLen - pos;
368 break;
370 pos -= tmpiter->buffer->SampleLen;
375 while(tmpiter && SrcBufferSize > SrcDataSize)
377 const ALbuffer *ALBuffer;
378 if((ALBuffer=tmpiter->buffer) != NULL)
380 const ALubyte *Data = ALBuffer->data;
381 ALuint DataSize = ALBuffer->SampleLen;
383 /* Skip the data already played */
384 if(DataSize <= pos)
385 pos -= DataSize;
386 else
388 Data += (pos*NumChannels + chan)*SampleSize;
389 DataSize -= pos;
390 pos -= pos;
392 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
393 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
394 ALBuffer->FmtType, DataSize);
395 SrcDataSize += DataSize;
398 tmpiter = tmpiter->next;
399 if(!tmpiter && Looping)
400 tmpiter = Source->queue;
401 else if(!tmpiter)
403 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
404 SrcDataSize += SrcBufferSize - SrcDataSize;
409 /* Now resample, then filter and mix to the appropriate outputs. */
410 ResampledData = Resample(
411 &SrcData[BufferPrePadding], DataPosFrac, increment,
412 Device->ResampledData, DstBufferSize
415 DirectParams *parms = &src->Direct;
416 const ALfloat *samples;
418 samples = DoFilters(
419 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
420 Device->FilteredData, ResampledData, DstBufferSize,
421 parms->Filters[chan].ActiveType
423 if(!src->IsHrtf)
424 Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan],
425 parms->Counter, OutPos, DstBufferSize);
426 else
427 HrtfMix(parms->OutBuffer, samples, parms->Counter, src->Offset,
428 OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
429 &parms->Mix.Hrtf.State[chan], DstBufferSize);
432 for(j = 0;j < Device->NumAuxSends;j++)
434 SendParams *parms = &src->Send[j];
435 const ALfloat *samples;
437 if(!parms->OutBuffer)
438 continue;
440 samples = DoFilters(
441 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
442 Device->FilteredData, ResampledData, DstBufferSize,
443 parms->Filters[chan].ActiveType
445 Mix(samples, 1, parms->OutBuffer, &parms->Gain,
446 parms->Counter, OutPos, DstBufferSize);
449 /* Update positions */
450 DataPosFrac += increment*DstBufferSize;
451 DataPosInt += DataPosFrac>>FRACTIONBITS;
452 DataPosFrac &= FRACTIONMASK;
454 OutPos += DstBufferSize;
455 src->Offset += DstBufferSize;
456 src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
457 for(j = 0;j < Device->NumAuxSends;j++)
458 src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
460 /* Handle looping sources */
461 while(1)
463 const ALbuffer *ALBuffer;
464 ALuint DataSize = 0;
465 ALuint LoopStart = 0;
466 ALuint LoopEnd = 0;
468 if((ALBuffer=BufferListItem->buffer) != NULL)
470 DataSize = ALBuffer->SampleLen;
471 LoopStart = ALBuffer->LoopStart;
472 LoopEnd = ALBuffer->LoopEnd;
473 if(LoopEnd > DataPosInt)
474 break;
477 if(Looping && Source->SourceType == AL_STATIC)
479 assert(LoopEnd > LoopStart);
480 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
481 break;
484 if(DataSize > DataPosInt)
485 break;
487 if(BufferListItem->next)
488 BufferListItem = BufferListItem->next;
489 else if(Looping)
490 BufferListItem = Source->queue;
491 else
493 State = AL_STOPPED;
494 BufferListItem = NULL;
495 DataPosInt = 0;
496 DataPosFrac = 0;
497 break;
500 DataPosInt -= DataSize;
502 } while(State == AL_PLAYING && OutPos < SamplesToDo);
504 /* Update source info */
505 Source->state = State;
506 Source->current_buffer = BufferListItem;
507 Source->position = DataPosInt;
508 Source->position_fraction = DataPosFrac;