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
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
40 static __inline ALfloat
point32(ALfloat val1
, ALfloat val2
, ALint frac
)
46 static __inline ALfloat
lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
48 val1
+= ((val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
))));
51 static __inline ALfloat
cos_lerp32(ALfloat val1
, ALfloat val2
, ALint frac
)
53 val1
+= ((val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5));
57 static __inline ALfloat
point16(ALfloat val1
, ALfloat val2
, ALint frac
)
59 return val1
/ 32767.0f
;
63 static __inline ALfloat
lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
65 val1
+= (val2
-val1
) * (frac
* (1.0/(1<<FRACTIONBITS
)));
66 return val1
/ 32767.0f
;
68 static __inline ALfloat
cos_lerp16(ALfloat val1
, ALfloat val2
, ALint frac
)
70 val1
+= (val2
-val1
) * ((1.0-cos(frac
* (1.0/(1<<FRACTIONBITS
)) * M_PI
)) * 0.5);
71 return val1
/ 32767.0f
;
75 #define DO_MIX_MONO(data,sampler) do { \
76 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
77 ALfloat *ClickRemoval, *PendingClicks; \
78 ALuint pos = DataPosInt; \
79 ALuint frac = DataPosFrac; \
80 ALfloat DrySend[OUTPUTCHANNELS]; \
86 DryBuffer = Device->DryBuffer; \
87 ClickRemoval = Device->ClickRemoval; \
88 PendingClicks = Device->PendingClicks; \
89 DryFilter = &Source->Params.iirFilter; \
90 for(i = 0;i < OUTPUTCHANNELS;i++) \
91 DrySend[i] = Source->Params.DryGains[i]; \
95 value = sampler(data[pos], data[pos+1], frac); \
97 value = lpFilter4PC(DryFilter, 0, value); \
98 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
99 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
100 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
101 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
102 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
103 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
104 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
105 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
107 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
109 /* First order interpolator */ \
110 value = sampler(data[pos], data[pos+1], frac); \
112 /* Direct path final mix buffer and panning */ \
113 value = lpFilter4P(DryFilter, 0, value); \
114 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
115 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
116 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
117 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
118 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
119 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
120 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
121 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
124 pos += frac>>FRACTIONBITS; \
125 frac &= FRACTIONMASK; \
128 if(j == SamplesToDo) \
134 ALuint64 pos64 = pos; \
135 pos64 <<= FRACTIONBITS; \
137 pos64 -= increment; \
138 p = pos64>>FRACTIONBITS; \
139 f = pos64&FRACTIONMASK; \
141 value = sampler(data[p], data[p+1], f); \
143 value = lpFilter4PC(DryFilter, 0, value); \
144 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
145 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
146 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
147 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
148 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
149 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
150 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
151 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
154 for(out = 0;out < Device->NumAuxSends;out++) \
157 ALfloat *WetBuffer; \
158 ALfloat *WetClickRemoval; \
159 ALfloat *WetPendingClicks; \
162 if(!Source->Send[out].Slot || \
163 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
166 WetSend = Source->Params.WetGains[out]; \
167 WetBuffer = Source->Send[out].Slot->WetBuffer; \
168 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
169 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
170 WetFilter = &Source->Params.Send[out].iirFilter; \
173 frac = DataPosFrac; \
178 value = sampler(data[pos], data[pos+1], frac); \
180 value = lpFilter2PC(WetFilter, 0, value); \
181 WetClickRemoval[0] -= value*WetSend; \
183 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
185 /* First order interpolator */ \
186 value = sampler(data[pos], data[pos+1], frac); \
188 /* Room path final mix buffer and panning */ \
189 value = lpFilter2P(WetFilter, 0, value); \
190 WetBuffer[j] += value*WetSend; \
193 pos += frac>>FRACTIONBITS; \
194 frac &= FRACTIONMASK; \
197 if(j == SamplesToDo) \
203 ALuint64 pos64 = pos; \
204 pos64 <<= FRACTIONBITS; \
206 pos64 -= increment; \
207 p = pos64>>FRACTIONBITS; \
208 f = pos64&FRACTIONMASK; \
210 value = sampler(data[p], data[p+1], f); \
212 value = lpFilter2PC(WetFilter, 0, value); \
213 WetPendingClicks[0] += value*WetSend; \
217 DataPosFrac = frac; \
220 #define DO_MIX_STEREO(data,sampler) do { \
221 const ALfloat scaler = 1.0f/Channels; \
222 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
223 ALfloat *ClickRemoval, *PendingClicks; \
224 ALuint pos = DataPosInt; \
225 ALuint frac = DataPosFrac; \
226 ALfloat DrySend[OUTPUTCHANNELS]; \
232 DryBuffer = Device->DryBuffer; \
233 ClickRemoval = Device->ClickRemoval; \
234 PendingClicks = Device->PendingClicks; \
235 DryFilter = &Source->Params.iirFilter; \
236 for(i = 0;i < OUTPUTCHANNELS;i++) \
237 DrySend[i] = Source->Params.DryGains[i]; \
241 for(i = 0;i < Channels;i++) \
243 value = sampler(data[pos*Channels + i], \
244 data[(pos+1)*Channels + i], frac); \
246 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
247 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
248 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
249 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
252 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
254 for(i = 0;i < Channels;i++) \
256 value = sampler(data[pos*Channels + i], \
257 data[(pos+1)*Channels + i], frac); \
259 value = lpFilter2P(DryFilter, chans[i]*2, value); \
260 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
261 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
262 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
266 pos += frac>>FRACTIONBITS; \
267 frac &= FRACTIONMASK; \
270 if(j == SamplesToDo) \
276 ALuint64 pos64 = pos; \
277 pos64 <<= FRACTIONBITS; \
279 pos64 -= increment; \
280 p = pos64>>FRACTIONBITS; \
281 f = pos64&FRACTIONMASK; \
283 for(i = 0;i < Channels;i++) \
285 value = sampler(data[p*Channels + i], \
286 data[(p+1)*Channels + i], f); \
288 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
289 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
290 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
291 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
295 for(out = 0;out < Device->NumAuxSends;out++) \
298 ALfloat *WetBuffer; \
299 ALfloat *WetClickRemoval; \
300 ALfloat *WetPendingClicks; \
303 if(!Source->Send[out].Slot || \
304 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
307 WetSend = Source->Params.WetGains[out]; \
308 WetBuffer = Source->Send[out].Slot->WetBuffer; \
309 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
310 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
311 WetFilter = &Source->Params.Send[out].iirFilter; \
314 frac = DataPosFrac; \
319 for(i = 0;i < Channels;i++) \
321 value = sampler(data[pos*Channels + i], \
322 data[(pos+1)*Channels + i], frac); \
324 value = lpFilter1PC(WetFilter, chans[i], value); \
325 WetClickRemoval[0] -= value*WetSend * scaler; \
328 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
330 for(i = 0;i < Channels;i++) \
332 value = sampler(data[pos*Channels + i], \
333 data[(pos+1)*Channels + i], frac); \
335 value = lpFilter1P(WetFilter, chans[i], value); \
336 WetBuffer[j] += value*WetSend * scaler; \
340 pos += frac>>FRACTIONBITS; \
341 frac &= FRACTIONMASK; \
344 if(j == SamplesToDo) \
350 ALuint64 pos64 = pos; \
351 pos64 <<= FRACTIONBITS; \
353 pos64 -= increment; \
354 p = pos64>>FRACTIONBITS; \
355 f = pos64&FRACTIONMASK; \
357 for(i = 0;i < Channels;i++) \
359 value = sampler(data[p*Channels + i], \
360 data[(p+1)*Channels + i], f); \
362 value = lpFilter1PC(WetFilter, chans[i], value); \
363 WetPendingClicks[0] += value*WetSend * scaler; \
368 DataPosFrac = frac; \
371 #define DO_MIX_MC(data,sampler) do { \
372 const ALfloat scaler = 1.0f/Channels; \
373 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
374 ALfloat *ClickRemoval, *PendingClicks; \
375 ALuint pos = DataPosInt; \
376 ALuint frac = DataPosFrac; \
377 ALfloat DrySend[OUTPUTCHANNELS]; \
383 DryBuffer = Device->DryBuffer; \
384 ClickRemoval = Device->ClickRemoval; \
385 PendingClicks = Device->PendingClicks; \
386 DryFilter = &Source->Params.iirFilter; \
387 for(i = 0;i < OUTPUTCHANNELS;i++) \
388 DrySend[i] = Source->Params.DryGains[i]; \
392 for(i = 0;i < Channels;i++) \
394 value = sampler(data[pos*Channels + i], \
395 data[(pos+1)*Channels + i], frac); \
397 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
398 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
401 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
403 for(i = 0;i < Channels;i++) \
405 value = sampler(data[pos*Channels + i], \
406 data[(pos+1)*Channels + i], frac); \
408 value = lpFilter2P(DryFilter, chans[i]*2, value); \
409 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
413 pos += frac>>FRACTIONBITS; \
414 frac &= FRACTIONMASK; \
417 if(j == SamplesToDo) \
423 ALuint64 pos64 = pos; \
424 pos64 <<= FRACTIONBITS; \
426 pos64 -= increment; \
427 p = pos64>>FRACTIONBITS; \
428 f = pos64&FRACTIONMASK; \
430 for(i = 0;i < Channels;i++) \
432 value = sampler(data[p*Channels + i], \
433 data[(p+1)*Channels + i], f); \
435 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
436 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
440 for(out = 0;out < Device->NumAuxSends;out++) \
443 ALfloat *WetBuffer; \
444 ALfloat *WetClickRemoval; \
445 ALfloat *WetPendingClicks; \
448 if(!Source->Send[out].Slot || \
449 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
452 WetBuffer = Source->Send[out].Slot->WetBuffer; \
453 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
454 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
455 WetFilter = &Source->Params.Send[out].iirFilter; \
456 WetSend = Source->Params.WetGains[out]; \
459 frac = DataPosFrac; \
464 for(i = 0;i < Channels;i++) \
466 value = sampler(data[pos*Channels + i], \
467 data[(pos+1)*Channels + i], frac); \
469 value = lpFilter1PC(WetFilter, chans[i], value); \
470 WetClickRemoval[0] -= value*WetSend * scaler; \
473 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
475 for(i = 0;i < Channels;i++) \
477 value = sampler(data[pos*Channels + i], \
478 data[(pos+1)*Channels + i], frac); \
480 value = lpFilter1P(WetFilter, chans[i], value); \
481 WetBuffer[j] += value*WetSend * scaler; \
485 pos += frac>>FRACTIONBITS; \
486 frac &= FRACTIONMASK; \
489 if(j == SamplesToDo) \
495 ALuint64 pos64 = pos; \
496 pos64 <<= FRACTIONBITS; \
498 pos64 -= increment; \
499 p = pos64>>FRACTIONBITS; \
500 f = pos64&FRACTIONMASK; \
502 for(i = 0;i < Channels;i++) \
504 value = sampler(data[p*Channels + i], \
505 data[(p+1)*Channels + i], f); \
507 value = lpFilter1PC(WetFilter, chans[i], value); \
508 WetPendingClicks[0] += value*WetSend * scaler; \
513 DataPosFrac = frac; \
517 #define MIX_MONO(sampler) do { \
519 DO_MIX_MONO(Data.p32,sampler##32); \
520 else if(Bytes == 2) \
521 DO_MIX_MONO(Data.p16,sampler##16); \
524 #define MIX_STEREO(sampler) do { \
525 const int chans[] = { \
526 FRONT_LEFT, FRONT_RIGHT, \
527 SIDE_LEFT, SIDE_RIGHT, \
528 BACK_LEFT, BACK_RIGHT \
532 DO_MIX_STEREO(Data.p32,sampler##32); \
533 else if(Bytes == 2) \
534 DO_MIX_STEREO(Data.p16,sampler##16); \
537 #define MIX_MC(sampler,...) do { \
538 const int chans[] = { __VA_ARGS__ }; \
541 DO_MIX_MC(Data.p32,sampler##32); \
542 else if(Bytes == 2) \
543 DO_MIX_MC(Data.p16,sampler##16); \
547 #define MIX(sampler) do { \
553 case 2: /* Stereo */ \
554 MIX_STEREO(sampler); \
557 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
558 BACK_LEFT, BACK_RIGHT); \
561 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
563 BACK_LEFT, BACK_RIGHT); \
566 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
569 SIDE_LEFT, SIDE_RIGHT); \
572 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
574 BACK_LEFT, BACK_RIGHT, \
575 SIDE_LEFT, SIDE_RIGHT); \
581 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
583 ALbufferlistitem
*BufferListItem
;
584 ALint64 DataSize64
,DataPos64
;
586 ALuint DataPosInt
, DataPosFrac
;
587 ALuint BuffersPlayed
;
592 /* Get source info */
593 State
= Source
->state
;
594 BuffersPlayed
= Source
->BuffersPlayed
;
595 DataPosInt
= Source
->position
;
596 DataPosFrac
= Source
->position_fraction
;
597 Looping
= Source
->bLooping
;
599 /* Get current buffer queue item */
600 BufferListItem
= Source
->queue
;
601 for(i
= 0;i
< BuffersPlayed
;i
++)
602 BufferListItem
= BufferListItem
->next
;
606 const ALbuffer
*ALBuffer
;
613 ALuint LoopStart
= 0;
615 ALuint Channels
, Bytes
;
618 /* Get buffer info */
619 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
621 Data
.p8
= ALBuffer
->data
;
622 DataSize
= ALBuffer
->size
;
623 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
624 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
625 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
629 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
631 /* If current pos is beyond the loop range, do not loop */
632 if(DataPosInt
>= LoopEnd
)
636 LoopStart
= ALBuffer
->LoopStart
;
637 LoopEnd
= ALBuffer
->LoopEnd
;
642 if(DataPosInt
>= DataSize
)
645 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, BUFFER_PADDING
*Channels
*Bytes
);
646 if(BufferListItem
->next
)
648 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
649 if(NextBuf
&& NextBuf
->size
)
651 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
652 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
653 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
654 NextBuf
->data
, ulExtraSamples
);
659 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
660 if(NextBuf
&& NextBuf
->size
)
662 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
663 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
664 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
665 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
670 /* Figure out how many samples we can mix. */
671 increment
= Source
->Params
.Step
;
672 DataSize64
= LoopEnd
;
673 DataSize64
<<= FRACTIONBITS
;
674 DataPos64
= DataPosInt
;
675 DataPos64
<<= FRACTIONBITS
;
676 DataPos64
+= DataPosFrac
;
677 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
679 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
681 switch(Source
->Resampler
)
683 case POINT_RESAMPLER
:
685 case LINEAR_RESAMPLER
:
687 case COSINE_RESAMPLER
:
688 MIX(cos_lerp
); break;
695 /* Handle looping sources */
696 if(DataPosInt
>= LoopEnd
)
698 if(BufferListItem
->next
)
700 BufferListItem
= BufferListItem
->next
;
702 DataPosInt
-= DataSize
;
706 BufferListItem
= Source
->queue
;
708 if(Source
->lSourceType
== AL_STATIC
)
709 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
711 DataPosInt
-= DataSize
;
716 BufferListItem
= Source
->queue
;
717 BuffersPlayed
= Source
->BuffersInQueue
;
722 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
724 /* Update source info */
725 Source
->state
= State
;
726 Source
->BuffersPlayed
= BuffersPlayed
;
727 Source
->position
= DataPosInt
;
728 Source
->position_fraction
= DataPosFrac
;
729 Source
->Buffer
= BufferListItem
->buffer
;