Move the target effect slot to the SendParams struct
[openal-soft.git] / Alc / mixer.c
blobe6cab3be781875b9d46bca2305e0466d82aa892f
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"
39 #include "mixer_defs.h"
42 DryMixerFunc SelectDirectMixer(void)
44 #ifdef HAVE_SSE
45 if((CPUCapFlags&CPU_CAP_SSE))
46 return MixDirect_SSE;
47 #endif
48 #ifdef HAVE_NEON
49 if((CPUCapFlags&CPU_CAP_NEON))
50 return MixDirect_Neon;
51 #endif
53 return MixDirect_C;
56 DryMixerFunc SelectHrtfMixer(void)
58 #ifdef HAVE_SSE
59 if((CPUCapFlags&CPU_CAP_SSE))
60 return MixDirect_Hrtf_SSE;
61 #endif
62 #ifdef HAVE_NEON
63 if((CPUCapFlags&CPU_CAP_NEON))
64 return MixDirect_Hrtf_Neon;
65 #endif
67 return MixDirect_Hrtf_C;
70 WetMixerFunc SelectSendMixer(void)
72 #ifdef HAVE_SSE
73 if((CPUCapFlags&CPU_CAP_SSE))
74 return MixSend_SSE;
75 #endif
76 #ifdef HAVE_NEON
77 if((CPUCapFlags&CPU_CAP_NEON))
78 return MixSend_Neon;
79 #endif
81 return MixSend_C;
85 static __inline ALfloat Sample_ALbyte(ALbyte val)
86 { return val * (1.0f/127.0f); }
88 static __inline ALfloat Sample_ALshort(ALshort val)
89 { return val * (1.0f/32767.0f); }
91 static __inline ALfloat Sample_ALfloat(ALfloat val)
92 { return val; }
94 #define DECL_TEMPLATE(T) \
95 static void Load_##T(ALfloat *dst, const T *src, ALuint samples) \
96 { \
97 ALuint i; \
98 for(i = 0;i < samples;i++) \
99 dst[i] = Sample_##T(src[i]); \
102 DECL_TEMPLATE(ALbyte)
103 DECL_TEMPLATE(ALshort)
104 DECL_TEMPLATE(ALfloat)
106 #undef DECL_TEMPLATE
108 static void LoadStack(ALfloat *dst, const ALvoid *src, enum FmtType srctype, ALuint samples)
110 switch(srctype)
112 case FmtByte:
113 Load_ALbyte(dst, src, samples);
114 break;
115 case FmtShort:
116 Load_ALshort(dst, src, samples);
117 break;
118 case FmtFloat:
119 Load_ALfloat(dst, src, samples);
120 break;
124 static void SilenceStack(ALfloat *dst, ALuint samples)
126 ALuint i;
127 for(i = 0;i < samples;i++)
128 dst[i] = 0.0f;
132 static __inline ALfloat point32(const ALfloat *vals, ALint step, ALint frac)
133 { return vals[0]; (void)step; (void)frac; }
134 static __inline ALfloat lerp32(const ALfloat *vals, ALint step, ALint frac)
135 { return lerp(vals[0], vals[step], frac * (1.0f/FRACTIONONE)); }
136 static __inline ALfloat cubic32(const ALfloat *vals, ALint step, ALint frac)
137 { return cubic(vals[-step], vals[0], vals[step], vals[step+step],
138 frac * (1.0f/FRACTIONONE)); }
140 #define DECL_TEMPLATE(Sampler) \
141 static void Resample_##Sampler(const ALfloat *data, ALuint frac, \
142 ALuint increment, ALuint NumChannels, ALfloat *RESTRICT OutBuffer, \
143 ALuint BufferSize) \
145 ALuint pos = 0; \
146 ALfloat value; \
147 ALuint i; \
149 for(i = 0;i < BufferSize+1;i++) \
151 value = Sampler(data + pos*NumChannels, NumChannels, frac); \
152 OutBuffer[i] = value; \
154 frac += increment; \
155 pos += frac>>FRACTIONBITS; \
156 frac &= FRACTIONMASK; \
160 DECL_TEMPLATE(point32)
161 DECL_TEMPLATE(lerp32)
162 DECL_TEMPLATE(cubic32)
164 #undef DECL_TEMPLATE
166 static void Resample(enum Resampler Resampler, const ALfloat *data, ALuint frac,
167 ALuint increment, ALuint NumChannels,
168 ALfloat *RESTRICT OutBuffer, ALuint BufferSize)
170 if(increment == FRACTIONONE)
171 goto do_point;
172 switch(Resampler)
174 case PointResampler:
175 do_point:
176 Resample_point32(data, frac, increment, NumChannels,
177 OutBuffer, BufferSize);
178 break;
179 case LinearResampler:
180 Resample_lerp32(data, frac, increment, NumChannels,
181 OutBuffer, BufferSize);
182 break;
183 case CubicResampler:
184 Resample_cubic32(data, frac, increment, NumChannels,
185 OutBuffer, BufferSize);
186 break;
187 case ResamplerMax:
188 /* Shouldn't happen */
189 break;
194 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
196 ALbufferlistitem *BufferListItem;
197 ALuint DataPosInt, DataPosFrac;
198 ALuint BuffersPlayed;
199 ALboolean Looping;
200 ALuint increment;
201 enum Resampler Resampler;
202 ALenum State;
203 ALuint OutPos;
204 ALuint NumChannels;
205 ALuint FrameSize;
206 ALint64 DataSize64;
207 ALuint i, j;
209 /* Get source info */
210 State = Source->state;
211 BuffersPlayed = Source->BuffersPlayed;
212 DataPosInt = Source->position;
213 DataPosFrac = Source->position_fraction;
214 Looping = Source->Looping;
215 increment = Source->Params.Step;
216 Resampler = Source->Resampler;
217 NumChannels = Source->NumChannels;
218 FrameSize = NumChannels * Source->SampleSize;
220 /* Get current buffer queue item */
221 BufferListItem = Source->queue;
222 for(i = 0;i < BuffersPlayed;i++)
223 BufferListItem = BufferListItem->next;
225 OutPos = 0;
226 do {
227 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
228 const ALuint BufferPadding = ResamplerPadding[Resampler];
229 ALfloat StackData[BUFFERSIZE];
230 ALfloat *SrcData = StackData;
231 ALuint SrcDataSize = 0;
232 ALuint BufferSize;
234 /* Figure out how many buffer bytes will be needed */
235 DataSize64 = SamplesToDo-OutPos+1;
236 DataSize64 *= increment;
237 DataSize64 += DataPosFrac+FRACTIONMASK;
238 DataSize64 >>= FRACTIONBITS;
239 DataSize64 += BufferPadding+BufferPrePadding;
240 DataSize64 *= NumChannels;
242 BufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
243 BufferSize /= NumChannels;
245 if(Source->SourceType == AL_STATIC)
247 const ALbuffer *ALBuffer = Source->queue->buffer;
248 const ALubyte *Data = ALBuffer->data;
249 ALuint DataSize;
250 ALuint pos;
252 /* If current pos is beyond the loop range, do not loop */
253 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
255 Looping = AL_FALSE;
257 if(DataPosInt >= BufferPrePadding)
258 pos = DataPosInt - BufferPrePadding;
259 else
261 DataSize = BufferPrePadding - DataPosInt;
262 DataSize = minu(BufferSize, DataSize);
264 SilenceStack(&SrcData[SrcDataSize*NumChannels],
265 DataSize*NumChannels);
266 SrcDataSize += DataSize;
267 BufferSize -= DataSize;
269 pos = 0;
272 /* Copy what's left to play in the source buffer, and clear the
273 * rest of the temp buffer */
274 DataSize = ALBuffer->SampleLen - pos;
275 DataSize = minu(BufferSize, DataSize);
277 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[pos*FrameSize],
278 ALBuffer->FmtType, DataSize*NumChannels);
279 SrcDataSize += DataSize;
280 BufferSize -= DataSize;
282 SilenceStack(&SrcData[SrcDataSize*NumChannels],
283 BufferSize*NumChannels);
284 SrcDataSize += BufferSize;
285 BufferSize -= BufferSize;
287 else
289 ALuint LoopStart = ALBuffer->LoopStart;
290 ALuint LoopEnd = ALBuffer->LoopEnd;
292 if(DataPosInt >= LoopStart)
294 pos = DataPosInt-LoopStart;
295 while(pos < BufferPrePadding)
296 pos += LoopEnd-LoopStart;
297 pos -= BufferPrePadding;
298 pos += LoopStart;
300 else if(DataPosInt >= BufferPrePadding)
301 pos = DataPosInt - BufferPrePadding;
302 else
304 DataSize = BufferPrePadding - DataPosInt;
305 DataSize = minu(BufferSize, DataSize);
307 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
308 SrcDataSize += DataSize;
309 BufferSize -= DataSize;
311 pos = 0;
314 /* Copy what's left of this loop iteration, then copy repeats
315 * of the loop section */
316 DataSize = LoopEnd - pos;
317 DataSize = minu(BufferSize, DataSize);
319 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[pos*FrameSize],
320 ALBuffer->FmtType, DataSize*NumChannels);
321 SrcDataSize += DataSize;
322 BufferSize -= DataSize;
324 DataSize = LoopEnd-LoopStart;
325 while(BufferSize > 0)
327 DataSize = minu(BufferSize, DataSize);
329 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[LoopStart*FrameSize],
330 ALBuffer->FmtType, DataSize*NumChannels);
331 SrcDataSize += DataSize;
332 BufferSize -= DataSize;
336 else
338 /* Crawl the buffer queue to fill in the temp buffer */
339 ALbufferlistitem *tmpiter = BufferListItem;
340 ALuint pos;
342 if(DataPosInt >= BufferPrePadding)
343 pos = DataPosInt - BufferPrePadding;
344 else
346 pos = BufferPrePadding - DataPosInt;
347 while(pos > 0)
349 if(!tmpiter->prev && !Looping)
351 ALuint DataSize = minu(BufferSize, pos);
353 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
354 SrcDataSize += DataSize;
355 BufferSize -= DataSize;
357 pos = 0;
358 break;
361 if(tmpiter->prev)
362 tmpiter = tmpiter->prev;
363 else
365 while(tmpiter->next)
366 tmpiter = tmpiter->next;
369 if(tmpiter->buffer)
371 if((ALuint)tmpiter->buffer->SampleLen > pos)
373 pos = tmpiter->buffer->SampleLen - pos;
374 break;
376 pos -= tmpiter->buffer->SampleLen;
381 while(tmpiter && BufferSize > 0)
383 const ALbuffer *ALBuffer;
384 if((ALBuffer=tmpiter->buffer) != NULL)
386 const ALubyte *Data = ALBuffer->data;
387 ALuint DataSize = ALBuffer->SampleLen;
389 /* Skip the data already played */
390 if(DataSize <= pos)
391 pos -= DataSize;
392 else
394 Data += pos*FrameSize;
395 DataSize -= pos;
396 pos -= pos;
398 DataSize = minu(BufferSize, DataSize);
399 LoadStack(&SrcData[SrcDataSize*NumChannels], Data,
400 ALBuffer->FmtType, DataSize*NumChannels);
401 SrcDataSize += DataSize;
402 BufferSize -= DataSize;
405 tmpiter = tmpiter->next;
406 if(!tmpiter && Looping)
407 tmpiter = Source->queue;
408 else if(!tmpiter)
410 SilenceStack(&SrcData[SrcDataSize*NumChannels], BufferSize*NumChannels);
411 SrcDataSize += BufferSize;
412 BufferSize -= BufferSize;
417 /* Figure out how many samples we can mix. */
418 DataSize64 = SrcDataSize;
419 DataSize64 -= BufferPadding+BufferPrePadding;
420 DataSize64 <<= FRACTIONBITS;
421 DataSize64 -= increment;
422 DataSize64 -= DataPosFrac;
424 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
425 BufferSize = minu(BufferSize, (SamplesToDo-OutPos));
427 SrcData += BufferPrePadding*NumChannels;
428 for(i = 0;i < NumChannels;i++)
430 ALfloat ResampledData[BUFFERSIZE];
432 Resample(Resampler, SrcData+i, DataPosFrac, increment,
433 NumChannels, ResampledData, BufferSize);
435 Source->Params.DryMix(Source, Device, &Source->Params.Direct,
436 ResampledData, i, OutPos, SamplesToDo,
437 BufferSize);
438 for(j = 0;j < Device->NumAuxSends;j++)
440 if(!Source->Params.Send[j].Slot)
441 continue;
442 Source->Params.WetMix(&Source->Params.Send[j], ResampledData, i,
443 OutPos, SamplesToDo, BufferSize);
446 for(i = 0;i < BufferSize;i++)
448 DataPosFrac += increment;
449 DataPosInt += DataPosFrac>>FRACTIONBITS;
450 DataPosFrac &= FRACTIONMASK;
451 OutPos++;
454 /* Handle looping sources */
455 while(1)
457 const ALbuffer *ALBuffer;
458 ALuint DataSize = 0;
459 ALuint LoopStart = 0;
460 ALuint LoopEnd = 0;
462 if((ALBuffer=BufferListItem->buffer) != NULL)
464 DataSize = ALBuffer->SampleLen;
465 LoopStart = ALBuffer->LoopStart;
466 LoopEnd = ALBuffer->LoopEnd;
467 if(LoopEnd > DataPosInt)
468 break;
471 if(Looping && Source->SourceType == AL_STATIC)
473 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
474 break;
477 if(DataSize > DataPosInt)
478 break;
480 if(BufferListItem->next)
482 BufferListItem = BufferListItem->next;
483 BuffersPlayed++;
485 else if(Looping)
487 BufferListItem = Source->queue;
488 BuffersPlayed = 0;
490 else
492 State = AL_STOPPED;
493 BufferListItem = Source->queue;
494 BuffersPlayed = Source->BuffersInQueue;
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->BuffersPlayed = BuffersPlayed;
507 Source->position = DataPosInt;
508 Source->position_fraction = DataPosFrac;
509 Source->Hrtf.Offset += OutPos;
510 if(State == AL_PLAYING)
512 Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos;
513 Source->Hrtf.Moving = AL_TRUE;
515 else
517 Source->Hrtf.Counter = 0;
518 Source->Hrtf.Moving = AL_FALSE;