Add a cast for MSVC
[openal-soft.git] / Alc / mixer.c
blob1cc3fe9d40560e20b8370ae09d58964828938621
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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
183 MixerFunc Mix;
184 HrtfMixerFunc HrtfMix;
185 ResamplerFunc Resample;
186 ALbufferlistitem *BufferListItem;
187 ALuint DataPosInt, DataPosFrac;
188 ALboolean Looping;
189 ALuint increment;
190 enum Resampler Resampler;
191 ALenum State;
192 ALuint OutPos;
193 ALuint NumChannels;
194 ALuint SampleSize;
195 ALint64 DataSize64;
196 ALuint chan, j;
198 /* Get source info */
199 State = Source->state;
200 BufferListItem = ATOMIC_LOAD(&Source->current_buffer);
201 DataPosInt = Source->position;
202 DataPosFrac = Source->position_fraction;
203 Looping = Source->Looping;
204 increment = voice->Step;
205 Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
206 NumChannels = Source->NumChannels;
207 SampleSize = Source->SampleSize;
209 Mix = SelectMixer();
210 HrtfMix = SelectHrtfMixer();
211 Resample = SelectResampler(Resampler, increment);
213 OutPos = 0;
214 do {
215 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
216 const ALuint BufferPadding = ResamplerPadding[Resampler];
217 ALuint SrcBufferSize, DstBufferSize;
219 /* Figure out how many buffer samples will be needed */
220 DataSize64 = SamplesToDo-OutPos;
221 DataSize64 *= increment;
222 DataSize64 += DataPosFrac+FRACTIONMASK;
223 DataSize64 >>= FRACTIONBITS;
224 DataSize64 += BufferPadding+BufferPrePadding;
226 SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
228 /* Figure out how many samples we can actually mix from this. */
229 DataSize64 = SrcBufferSize;
230 DataSize64 -= BufferPadding+BufferPrePadding;
231 DataSize64 <<= FRACTIONBITS;
232 DataSize64 -= DataPosFrac;
234 DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
235 DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
237 /* Some mixers like having a multiple of 4, so try to give that unless
238 * this is the last update. */
239 if(OutPos+DstBufferSize < SamplesToDo)
240 DstBufferSize &= ~3;
242 for(chan = 0;chan < NumChannels;chan++)
244 const ALfloat *ResampledData;
245 ALfloat *SrcData = Device->SourceData;
246 ALuint SrcDataSize = 0;
248 if(Source->SourceType == AL_STATIC)
250 const ALbuffer *ALBuffer = BufferListItem->buffer;
251 const ALubyte *Data = ALBuffer->data;
252 ALuint DataSize;
253 ALuint pos;
255 /* If current pos is beyond the loop range, do not loop */
256 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
258 Looping = AL_FALSE;
260 if(DataPosInt >= BufferPrePadding)
261 pos = DataPosInt - BufferPrePadding;
262 else
264 DataSize = BufferPrePadding - DataPosInt;
265 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
267 SilenceSamples(&SrcData[SrcDataSize], DataSize);
268 SrcDataSize += DataSize;
270 pos = 0;
273 /* Copy what's left to play in the source buffer, and clear the
274 * rest of the temp buffer */
275 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
277 LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
278 NumChannels, ALBuffer->FmtType, DataSize);
279 SrcDataSize += DataSize;
281 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
282 SrcDataSize += SrcBufferSize - SrcDataSize;
284 else
286 ALuint LoopStart = ALBuffer->LoopStart;
287 ALuint LoopEnd = ALBuffer->LoopEnd;
289 if(DataPosInt >= LoopStart)
291 pos = DataPosInt-LoopStart;
292 while(pos < BufferPrePadding)
293 pos += LoopEnd-LoopStart;
294 pos -= BufferPrePadding;
295 pos += LoopStart;
297 else if(DataPosInt >= BufferPrePadding)
298 pos = DataPosInt - BufferPrePadding;
299 else
301 DataSize = BufferPrePadding - DataPosInt;
302 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
304 SilenceSamples(&SrcData[SrcDataSize], DataSize);
305 SrcDataSize += DataSize;
307 pos = 0;
310 /* Copy what's left of this loop iteration, then copy repeats
311 * of the loop section */
312 DataSize = LoopEnd - pos;
313 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
315 LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
316 NumChannels, ALBuffer->FmtType, DataSize);
317 SrcDataSize += DataSize;
319 DataSize = LoopEnd-LoopStart;
320 while(SrcBufferSize > SrcDataSize)
322 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
324 LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
325 NumChannels, ALBuffer->FmtType, DataSize);
326 SrcDataSize += DataSize;
330 else
332 /* Crawl the buffer queue to fill in the temp buffer */
333 ALbufferlistitem *tmpiter = BufferListItem;
334 ALuint pos;
336 if(DataPosInt >= BufferPrePadding)
337 pos = DataPosInt - BufferPrePadding;
338 else
340 pos = BufferPrePadding - DataPosInt;
341 while(pos > 0)
343 ALbufferlistitem *prev;
344 if((prev=tmpiter->prev) != NULL)
345 tmpiter = prev;
346 else if(Looping)
348 while(tmpiter->next)
349 tmpiter = tmpiter->next;
351 else
353 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
355 SilenceSamples(&SrcData[SrcDataSize], DataSize);
356 SrcDataSize += DataSize;
358 pos = 0;
359 break;
362 if(tmpiter->buffer)
364 if((ALuint)tmpiter->buffer->SampleLen > pos)
366 pos = tmpiter->buffer->SampleLen - pos;
367 break;
369 pos -= tmpiter->buffer->SampleLen;
374 while(tmpiter && SrcBufferSize > SrcDataSize)
376 const ALbuffer *ALBuffer;
377 if((ALBuffer=tmpiter->buffer) != NULL)
379 const ALubyte *Data = ALBuffer->data;
380 ALuint DataSize = ALBuffer->SampleLen;
382 /* Skip the data already played */
383 if(DataSize <= pos)
384 pos -= DataSize;
385 else
387 Data += (pos*NumChannels + chan)*SampleSize;
388 DataSize -= pos;
389 pos -= pos;
391 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
392 LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
393 ALBuffer->FmtType, DataSize);
394 SrcDataSize += DataSize;
397 tmpiter = tmpiter->next;
398 if(!tmpiter && Looping)
399 tmpiter = ATOMIC_LOAD(&Source->queue);
400 else if(!tmpiter)
402 SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
403 SrcDataSize += SrcBufferSize - SrcDataSize;
408 /* Now resample, then filter and mix to the appropriate outputs. */
409 ResampledData = Resample(
410 &SrcData[BufferPrePadding], DataPosFrac, increment,
411 Device->ResampledData, DstBufferSize
414 DirectParams *parms = &voice->Direct;
415 const ALfloat *samples;
417 samples = DoFilters(
418 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
419 Device->FilteredData, ResampledData, DstBufferSize,
420 parms->Filters[chan].ActiveType
422 if(!voice->IsHrtf)
423 Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan],
424 parms->Counter, OutPos, DstBufferSize);
425 else
426 HrtfMix(parms->OutBuffer, samples, parms->Counter, voice->Offset,
427 OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
428 &parms->Mix.Hrtf.State[chan], DstBufferSize);
431 for(j = 0;j < Device->NumAuxSends;j++)
433 SendParams *parms = &voice->Send[j];
434 const ALfloat *samples;
436 if(!parms->OutBuffer)
437 continue;
439 samples = DoFilters(
440 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
441 Device->FilteredData, ResampledData, DstBufferSize,
442 parms->Filters[chan].ActiveType
444 Mix(samples, 1, parms->OutBuffer, &parms->Gain,
445 parms->Counter, OutPos, DstBufferSize);
448 /* Update positions */
449 DataPosFrac += increment*DstBufferSize;
450 DataPosInt += DataPosFrac>>FRACTIONBITS;
451 DataPosFrac &= FRACTIONMASK;
453 OutPos += DstBufferSize;
454 voice->Offset += DstBufferSize;
455 voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize;
456 for(j = 0;j < Device->NumAuxSends;j++)
457 voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize;
459 /* Handle looping sources */
460 while(1)
462 const ALbuffer *ALBuffer;
463 ALuint DataSize = 0;
464 ALuint LoopStart = 0;
465 ALuint LoopEnd = 0;
467 if((ALBuffer=BufferListItem->buffer) != NULL)
469 DataSize = ALBuffer->SampleLen;
470 LoopStart = ALBuffer->LoopStart;
471 LoopEnd = ALBuffer->LoopEnd;
472 if(LoopEnd > DataPosInt)
473 break;
476 if(Looping && Source->SourceType == AL_STATIC)
478 assert(LoopEnd > LoopStart);
479 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
480 break;
483 if(DataSize > DataPosInt)
484 break;
486 if(!(BufferListItem=BufferListItem->next))
488 if(Looping)
489 BufferListItem = ATOMIC_LOAD(&Source->queue);
490 else
492 State = AL_STOPPED;
493 BufferListItem = NULL;
494 DataPosInt = 0;
495 DataPosFrac = 0;
496 break;
500 DataPosInt -= DataSize;
502 } while(State == AL_PLAYING && OutPos < SamplesToDo);
504 /* Update source info */
505 Source->state = State;
506 ATOMIC_STORE(&Source->current_buffer, BufferListItem);
507 Source->position = DataPosInt;
508 Source->position_fraction = DataPosFrac;