Combine the direct and send mixers
[openal-soft.git] / Alc / mixer.c
blob1ecc8d885ef497d47d433b76c632cc5d6c44cbe8
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 extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
43 static inline ALfloat Sample_ALbyte(ALbyte val)
44 { return val * (1.0f/127.0f); }
46 static inline ALfloat Sample_ALshort(ALshort val)
47 { return val * (1.0f/32767.0f); }
49 static inline ALfloat Sample_ALfloat(ALfloat val)
50 { return val; }
52 #define DECL_TEMPLATE(T) \
53 static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
54 { \
55 ALuint i; \
56 for(i = 0;i < samples;i++) \
57 dst[i] = Sample_##T(src[i*srcstep]); \
60 DECL_TEMPLATE(ALbyte)
61 DECL_TEMPLATE(ALshort)
62 DECL_TEMPLATE(ALfloat)
64 #undef DECL_TEMPLATE
66 static void LoadData(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
68 switch(srctype)
70 case FmtByte:
71 Load_ALbyte(dst, src, srcstep, samples);
72 break;
73 case FmtShort:
74 Load_ALshort(dst, src, srcstep, samples);
75 break;
76 case FmtFloat:
77 Load_ALfloat(dst, src, srcstep, samples);
78 break;
82 static void SilenceData(ALfloat *dst, ALuint samples)
84 ALuint i;
85 for(i = 0;i < samples;i++)
86 dst[i] = 0.0f;
90 static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
91 ALfloat *restrict dst, const ALfloat *restrict src,
92 ALuint numsamples, enum ActiveFilters type)
94 ALuint i;
95 switch(type)
97 case AF_None:
98 break;
100 case AF_LowPass:
101 ALfilterState_process(lpfilter, dst, src, numsamples);
102 return dst;
103 case AF_HighPass:
104 ALfilterState_process(hpfilter, dst, src, numsamples);
105 return dst;
107 case AF_BandPass:
108 for(i = 0;i < numsamples;)
110 ALfloat temp[64];
111 ALuint todo = minu(64, numsamples-i);
113 ALfilterState_process(lpfilter, temp, src+i, todo);
114 ALfilterState_process(hpfilter, dst+i, temp, todo);
115 i += todo;
117 return dst;
119 return src;
123 ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
125 ALsource *Source = src->Source;
126 ALbufferlistitem *BufferListItem;
127 ALuint DataPosInt, DataPosFrac;
128 ALboolean Looping;
129 ALuint increment;
130 enum Resampler Resampler;
131 ALenum State;
132 ALuint OutPos;
133 ALuint NumChannels;
134 ALuint SampleSize;
135 ALint64 DataSize64;
136 ALuint chan, j;
138 /* Get source info */
139 State = Source->state;
140 BufferListItem = Source->current_buffer;
141 DataPosInt = Source->position;
142 DataPosFrac = Source->position_fraction;
143 Looping = Source->Looping;
144 increment = src->Step;
145 Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
146 NumChannels = Source->NumChannels;
147 SampleSize = Source->SampleSize;
149 /* Get current buffer queue item */
151 OutPos = 0;
152 do {
153 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
154 const ALuint BufferPadding = ResamplerPadding[Resampler];
155 ALuint SrcBufferSize, DstBufferSize;
157 /* Figure out how many buffer samples will be needed */
158 DataSize64 = SamplesToDo-OutPos;
159 DataSize64 *= increment;
160 DataSize64 += DataPosFrac+FRACTIONMASK;
161 DataSize64 >>= FRACTIONBITS;
162 DataSize64 += BufferPadding+BufferPrePadding;
164 SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
166 /* Figure out how many samples we can actually mix from this. */
167 DataSize64 = SrcBufferSize;
168 DataSize64 -= BufferPadding+BufferPrePadding;
169 DataSize64 <<= FRACTIONBITS;
170 DataSize64 -= DataPosFrac;
172 DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
173 DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
175 /* Some mixers like having a multiple of 4, so try to give that unless
176 * this is the last update. */
177 if(OutPos+DstBufferSize < SamplesToDo)
178 DstBufferSize &= ~3;
180 for(chan = 0;chan < NumChannels;chan++)
182 const ALfloat *ResampledData;
183 ALfloat *SrcData = Device->SourceData;
184 ALuint SrcDataSize = 0;
186 if(Source->SourceType == AL_STATIC)
188 const ALbuffer *ALBuffer = BufferListItem->buffer;
189 const ALubyte *Data = ALBuffer->data;
190 ALuint DataSize;
191 ALuint pos;
193 /* If current pos is beyond the loop range, do not loop */
194 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
196 Looping = AL_FALSE;
198 if(DataPosInt >= BufferPrePadding)
199 pos = DataPosInt - BufferPrePadding;
200 else
202 DataSize = BufferPrePadding - DataPosInt;
203 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
205 SilenceData(&SrcData[SrcDataSize], DataSize);
206 SrcDataSize += DataSize;
208 pos = 0;
211 /* Copy what's left to play in the source buffer, and clear the
212 * rest of the temp buffer */
213 DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
215 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
216 NumChannels, ALBuffer->FmtType, DataSize);
217 SrcDataSize += DataSize;
219 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
220 SrcDataSize += SrcBufferSize - SrcDataSize;
222 else
224 ALuint LoopStart = ALBuffer->LoopStart;
225 ALuint LoopEnd = ALBuffer->LoopEnd;
227 if(DataPosInt >= LoopStart)
229 pos = DataPosInt-LoopStart;
230 while(pos < BufferPrePadding)
231 pos += LoopEnd-LoopStart;
232 pos -= BufferPrePadding;
233 pos += LoopStart;
235 else if(DataPosInt >= BufferPrePadding)
236 pos = DataPosInt - BufferPrePadding;
237 else
239 DataSize = BufferPrePadding - DataPosInt;
240 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
242 SilenceData(&SrcData[SrcDataSize], DataSize);
243 SrcDataSize += DataSize;
245 pos = 0;
248 /* Copy what's left of this loop iteration, then copy repeats
249 * of the loop section */
250 DataSize = LoopEnd - pos;
251 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
253 LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
254 NumChannels, ALBuffer->FmtType, DataSize);
255 SrcDataSize += DataSize;
257 DataSize = LoopEnd-LoopStart;
258 while(SrcBufferSize > SrcDataSize)
260 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
262 LoadData(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
263 NumChannels, ALBuffer->FmtType, DataSize);
264 SrcDataSize += DataSize;
268 else
270 /* Crawl the buffer queue to fill in the temp buffer */
271 ALbufferlistitem *tmpiter = BufferListItem;
272 ALuint pos;
274 if(DataPosInt >= BufferPrePadding)
275 pos = DataPosInt - BufferPrePadding;
276 else
278 pos = BufferPrePadding - DataPosInt;
279 while(pos > 0)
281 ALbufferlistitem *prev;
282 if((prev=tmpiter->prev) != NULL)
283 tmpiter = prev;
284 else if(Looping)
286 while(tmpiter->next)
287 tmpiter = tmpiter->next;
289 else
291 ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
293 SilenceData(&SrcData[SrcDataSize], DataSize);
294 SrcDataSize += DataSize;
296 pos = 0;
297 break;
300 if(tmpiter->buffer)
302 if((ALuint)tmpiter->buffer->SampleLen > pos)
304 pos = tmpiter->buffer->SampleLen - pos;
305 break;
307 pos -= tmpiter->buffer->SampleLen;
312 while(tmpiter && SrcBufferSize > SrcDataSize)
314 const ALbuffer *ALBuffer;
315 if((ALBuffer=tmpiter->buffer) != NULL)
317 const ALubyte *Data = ALBuffer->data;
318 ALuint DataSize = ALBuffer->SampleLen;
320 /* Skip the data already played */
321 if(DataSize <= pos)
322 pos -= DataSize;
323 else
325 Data += (pos*NumChannels + chan)*SampleSize;
326 DataSize -= pos;
327 pos -= pos;
329 DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
330 LoadData(&SrcData[SrcDataSize], Data, NumChannels,
331 ALBuffer->FmtType, DataSize);
332 SrcDataSize += DataSize;
335 tmpiter = tmpiter->next;
336 if(!tmpiter && Looping)
337 tmpiter = Source->queue;
338 else if(!tmpiter)
340 SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
341 SrcDataSize += SrcBufferSize - SrcDataSize;
346 /* Now resample, then filter and mix to the appropriate outputs. */
347 ResampledData = src->Resample(
348 &SrcData[BufferPrePadding], DataPosFrac, increment,
349 Device->ResampledData, DstBufferSize
352 DirectParams *parms = &src->Direct;
353 const ALfloat *samples;
355 samples = DoFilters(
356 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
357 Device->FilteredData, ResampledData, DstBufferSize,
358 parms->Filters[chan].ActiveType
360 if(!src->IsHrtf)
361 src->Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan],
362 parms->Counter, OutPos, DstBufferSize);
363 else
364 src->HrtfMix(
365 parms->OutBuffer, samples, parms->Counter, src->Offset,
366 OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
367 &parms->Mix.Hrtf.State[chan], DstBufferSize
371 for(j = 0;j < Device->NumAuxSends;j++)
373 SendParams *parms = &src->Send[j];
374 const ALfloat *samples;
376 if(!parms->OutBuffer)
377 continue;
379 samples = DoFilters(
380 &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
381 Device->FilteredData, ResampledData, DstBufferSize,
382 parms->Filters[chan].ActiveType
384 src->Mix(samples, 1, parms->OutBuffer, &parms->Gain,
385 parms->Counter, OutPos, DstBufferSize);
388 /* Update positions */
389 DataPosFrac += increment*DstBufferSize;
390 DataPosInt += DataPosFrac>>FRACTIONBITS;
391 DataPosFrac &= FRACTIONMASK;
393 OutPos += DstBufferSize;
394 src->Offset += DstBufferSize;
395 src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
396 for(j = 0;j < Device->NumAuxSends;j++)
397 src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
399 /* Handle looping sources */
400 while(1)
402 const ALbuffer *ALBuffer;
403 ALuint DataSize = 0;
404 ALuint LoopStart = 0;
405 ALuint LoopEnd = 0;
407 if((ALBuffer=BufferListItem->buffer) != NULL)
409 DataSize = ALBuffer->SampleLen;
410 LoopStart = ALBuffer->LoopStart;
411 LoopEnd = ALBuffer->LoopEnd;
412 if(LoopEnd > DataPosInt)
413 break;
416 if(Looping && Source->SourceType == AL_STATIC)
418 assert(LoopEnd > LoopStart);
419 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
420 break;
423 if(DataSize > DataPosInt)
424 break;
426 if(BufferListItem->next)
427 BufferListItem = BufferListItem->next;
428 else if(Looping)
429 BufferListItem = Source->queue;
430 else
432 State = AL_STOPPED;
433 BufferListItem = NULL;
434 DataPosInt = 0;
435 DataPosFrac = 0;
436 break;
439 DataPosInt -= DataSize;
441 } while(State == AL_PLAYING && OutPos < SamplesToDo);
443 /* Update source info */
444 Source->state = State;
445 Source->current_buffer = BufferListItem;
446 Source->position = DataPosInt;
447 Source->position_fraction = DataPosFrac;