Fix matrix multiply used by the SSE cubic resampler
[openal-soft/openal-hmr.git] / Alc / mixer.c
blob3ef41aa9b439f1f13a6fa9d4cd7e1604adf1f106
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 samples) \
51 { \
52 ALuint i; \
53 for(i = 0;i < samples;i++) \
54 dst[i] = Sample_##T(src[i]); \
57 DECL_TEMPLATE(ALbyte)
58 DECL_TEMPLATE(ALshort)
59 DECL_TEMPLATE(ALfloat)
61 #undef DECL_TEMPLATE
63 static void LoadStack(ALfloat *dst, const ALvoid *src, enum FmtType srctype, ALuint samples)
65 switch(srctype)
67 case FmtByte:
68 Load_ALbyte(dst, src, samples);
69 break;
70 case FmtShort:
71 Load_ALshort(dst, src, samples);
72 break;
73 case FmtFloat:
74 Load_ALfloat(dst, src, samples);
75 break;
79 static void SilenceStack(ALfloat *dst, ALuint samples)
81 ALuint i;
82 for(i = 0;i < samples;i++)
83 dst[i] = 0.0f;
87 static void Filter2P(FILTER *filter, ALuint chan, ALfloat *RESTRICT dst,
88 const ALfloat *RESTRICT src, ALuint numsamples)
90 ALuint i;
91 for(i = 0;i < numsamples;i++)
92 dst[i] = lpFilter2P(filter, chan, src[i]);
93 dst[i] = lpFilter2PC(filter, chan, src[i]);
97 ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
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 FrameSize;
109 ALint64 DataSize64;
110 ALuint i, 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 = Source->Params.Step;
119 Resampler = Source->Resampler;
120 NumChannels = Source->NumChannels;
121 FrameSize = NumChannels * Source->SampleSize;
123 /* Get current buffer queue item */
124 BufferListItem = Source->queue;
125 for(i = 0;i < BuffersPlayed;i++)
126 BufferListItem = BufferListItem->next;
128 OutPos = 0;
129 do {
130 const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
131 const ALuint BufferPadding = ResamplerPadding[Resampler];
132 ALfloat StackData[BUFFERSIZE];
133 ALfloat *SrcData = StackData;
134 ALuint SrcDataSize = 0;
135 ALuint BufferSize;
137 /* Figure out how many buffer bytes will be needed */
138 DataSize64 = SamplesToDo-OutPos+1;
139 DataSize64 *= increment;
140 DataSize64 += DataPosFrac+FRACTIONMASK;
141 DataSize64 >>= FRACTIONBITS;
142 DataSize64 += BufferPadding+BufferPrePadding;
143 DataSize64 *= NumChannels;
145 BufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
146 BufferSize /= NumChannels;
148 if(Source->SourceType == AL_STATIC)
150 const ALbuffer *ALBuffer = Source->queue->buffer;
151 const ALubyte *Data = ALBuffer->data;
152 ALuint DataSize;
153 ALuint pos;
155 /* If current pos is beyond the loop range, do not loop */
156 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
158 Looping = AL_FALSE;
160 if(DataPosInt >= BufferPrePadding)
161 pos = DataPosInt - BufferPrePadding;
162 else
164 DataSize = BufferPrePadding - DataPosInt;
165 DataSize = minu(BufferSize, DataSize);
167 SilenceStack(&SrcData[SrcDataSize*NumChannels],
168 DataSize*NumChannels);
169 SrcDataSize += DataSize;
170 BufferSize -= DataSize;
172 pos = 0;
175 /* Copy what's left to play in the source buffer, and clear the
176 * rest of the temp buffer */
177 DataSize = ALBuffer->SampleLen - pos;
178 DataSize = minu(BufferSize, DataSize);
180 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[pos*FrameSize],
181 ALBuffer->FmtType, DataSize*NumChannels);
182 SrcDataSize += DataSize;
183 BufferSize -= DataSize;
185 SilenceStack(&SrcData[SrcDataSize*NumChannels],
186 BufferSize*NumChannels);
187 SrcDataSize += BufferSize;
188 BufferSize -= BufferSize;
190 else
192 ALuint LoopStart = ALBuffer->LoopStart;
193 ALuint LoopEnd = ALBuffer->LoopEnd;
195 if(DataPosInt >= LoopStart)
197 pos = DataPosInt-LoopStart;
198 while(pos < BufferPrePadding)
199 pos += LoopEnd-LoopStart;
200 pos -= BufferPrePadding;
201 pos += LoopStart;
203 else if(DataPosInt >= BufferPrePadding)
204 pos = DataPosInt - BufferPrePadding;
205 else
207 DataSize = BufferPrePadding - DataPosInt;
208 DataSize = minu(BufferSize, DataSize);
210 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
211 SrcDataSize += DataSize;
212 BufferSize -= DataSize;
214 pos = 0;
217 /* Copy what's left of this loop iteration, then copy repeats
218 * of the loop section */
219 DataSize = LoopEnd - pos;
220 DataSize = minu(BufferSize, DataSize);
222 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[pos*FrameSize],
223 ALBuffer->FmtType, DataSize*NumChannels);
224 SrcDataSize += DataSize;
225 BufferSize -= DataSize;
227 DataSize = LoopEnd-LoopStart;
228 while(BufferSize > 0)
230 DataSize = minu(BufferSize, DataSize);
232 LoadStack(&SrcData[SrcDataSize*NumChannels], &Data[LoopStart*FrameSize],
233 ALBuffer->FmtType, DataSize*NumChannels);
234 SrcDataSize += DataSize;
235 BufferSize -= DataSize;
239 else
241 /* Crawl the buffer queue to fill in the temp buffer */
242 ALbufferlistitem *tmpiter = BufferListItem;
243 ALuint pos;
245 if(DataPosInt >= BufferPrePadding)
246 pos = DataPosInt - BufferPrePadding;
247 else
249 pos = BufferPrePadding - DataPosInt;
250 while(pos > 0)
252 if(!tmpiter->prev && !Looping)
254 ALuint DataSize = minu(BufferSize, pos);
256 SilenceStack(&SrcData[SrcDataSize*NumChannels], DataSize*NumChannels);
257 SrcDataSize += DataSize;
258 BufferSize -= DataSize;
260 pos = 0;
261 break;
264 if(tmpiter->prev)
265 tmpiter = tmpiter->prev;
266 else
268 while(tmpiter->next)
269 tmpiter = tmpiter->next;
272 if(tmpiter->buffer)
274 if((ALuint)tmpiter->buffer->SampleLen > pos)
276 pos = tmpiter->buffer->SampleLen - pos;
277 break;
279 pos -= tmpiter->buffer->SampleLen;
284 while(tmpiter && BufferSize > 0)
286 const ALbuffer *ALBuffer;
287 if((ALBuffer=tmpiter->buffer) != NULL)
289 const ALubyte *Data = ALBuffer->data;
290 ALuint DataSize = ALBuffer->SampleLen;
292 /* Skip the data already played */
293 if(DataSize <= pos)
294 pos -= DataSize;
295 else
297 Data += pos*FrameSize;
298 DataSize -= pos;
299 pos -= pos;
301 DataSize = minu(BufferSize, DataSize);
302 LoadStack(&SrcData[SrcDataSize*NumChannels], Data,
303 ALBuffer->FmtType, DataSize*NumChannels);
304 SrcDataSize += DataSize;
305 BufferSize -= DataSize;
308 tmpiter = tmpiter->next;
309 if(!tmpiter && Looping)
310 tmpiter = Source->queue;
311 else if(!tmpiter)
313 SilenceStack(&SrcData[SrcDataSize*NumChannels], BufferSize*NumChannels);
314 SrcDataSize += BufferSize;
315 BufferSize -= BufferSize;
320 /* Figure out how many samples we can mix. */
321 DataSize64 = SrcDataSize;
322 DataSize64 -= BufferPadding+BufferPrePadding;
323 DataSize64 <<= FRACTIONBITS;
324 DataSize64 -= increment;
325 DataSize64 -= DataPosFrac;
327 BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
328 BufferSize = minu(BufferSize, (SamplesToDo-OutPos));
330 /* Some mixers like having a multiple of 4, so try to give that unless
331 * this is the last update. */
332 if(OutPos+BufferSize < SamplesToDo)
333 BufferSize &= ~3;
335 SrcData += BufferPrePadding*NumChannels;
336 for(i = 0;i < NumChannels;i++)
338 DirectParams *directparms = &Source->Params.Direct;
339 ALIGN(16) ALfloat FilteredData[BUFFERSIZE];
340 ALIGN(16) ALfloat ResampledData[BUFFERSIZE];
342 Source->Params.Resample(SrcData+i, DataPosFrac, increment,
343 NumChannels, ResampledData, BufferSize);
345 Filter2P(&directparms->iirFilter, i, FilteredData, ResampledData,
346 BufferSize);
348 Source->Params.DryMix(Source, Device, directparms,
349 FilteredData, i, OutPos, SamplesToDo,
350 BufferSize);
352 for(j = 0;j < Device->NumAuxSends;j++)
354 SendParams *sendparms = &Source->Params.Send[j];
355 if(!sendparms->Slot)
356 continue;
358 Filter2P(&sendparms->iirFilter, i, FilteredData, ResampledData,
359 BufferSize);
360 Source->Params.WetMix(sendparms, FilteredData, OutPos,
361 SamplesToDo, BufferSize);
364 for(i = 0;i < BufferSize;i++)
366 DataPosFrac += increment;
367 DataPosInt += DataPosFrac>>FRACTIONBITS;
368 DataPosFrac &= FRACTIONMASK;
369 OutPos++;
372 /* Handle looping sources */
373 while(1)
375 const ALbuffer *ALBuffer;
376 ALuint DataSize = 0;
377 ALuint LoopStart = 0;
378 ALuint LoopEnd = 0;
380 if((ALBuffer=BufferListItem->buffer) != NULL)
382 DataSize = ALBuffer->SampleLen;
383 LoopStart = ALBuffer->LoopStart;
384 LoopEnd = ALBuffer->LoopEnd;
385 if(LoopEnd > DataPosInt)
386 break;
389 if(Looping && Source->SourceType == AL_STATIC)
391 DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
392 break;
395 if(DataSize > DataPosInt)
396 break;
398 if(BufferListItem->next)
400 BufferListItem = BufferListItem->next;
401 BuffersPlayed++;
403 else if(Looping)
405 BufferListItem = Source->queue;
406 BuffersPlayed = 0;
408 else
410 State = AL_STOPPED;
411 BufferListItem = Source->queue;
412 BuffersPlayed = Source->BuffersInQueue;
413 DataPosInt = 0;
414 DataPosFrac = 0;
415 break;
418 DataPosInt -= DataSize;
420 } while(State == AL_PLAYING && OutPos < SamplesToDo);
422 /* Update source info */
423 Source->state = State;
424 Source->BuffersPlayed = BuffersPlayed;
425 Source->position = DataPosInt;
426 Source->position_fraction = DataPosFrac;
427 Source->Hrtf.Offset += OutPos;
428 if(State == AL_PLAYING)
430 Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos;
431 Source->Hrtf.Moving = AL_TRUE;
433 else
435 Source->Hrtf.Counter = 0;
436 Source->Hrtf.Moving = AL_FALSE;