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; \
79 ALfloat DrySend[OUTPUTCHANNELS]; \
85 DryBuffer = Device->DryBuffer; \
86 ClickRemoval = Device->ClickRemoval; \
87 PendingClicks = Device->PendingClicks; \
88 DryFilter = &Source->Params.iirFilter; \
89 for(i = 0;i < OUTPUTCHANNELS;i++) \
90 DrySend[i] = Source->Params.DryGains[i]; \
97 value = sampler(data[pos], data[pos+1], frac); \
99 value = lpFilter4PC(DryFilter, 0, value); \
100 ClickRemoval[FRONT_LEFT] -= value*DrySend[FRONT_LEFT]; \
101 ClickRemoval[FRONT_RIGHT] -= value*DrySend[FRONT_RIGHT]; \
102 ClickRemoval[SIDE_LEFT] -= value*DrySend[SIDE_LEFT]; \
103 ClickRemoval[SIDE_RIGHT] -= value*DrySend[SIDE_RIGHT]; \
104 ClickRemoval[BACK_LEFT] -= value*DrySend[BACK_LEFT]; \
105 ClickRemoval[BACK_RIGHT] -= value*DrySend[BACK_RIGHT]; \
106 ClickRemoval[FRONT_CENTER] -= value*DrySend[FRONT_CENTER]; \
107 ClickRemoval[BACK_CENTER] -= value*DrySend[BACK_CENTER]; \
109 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
111 /* First order interpolator */ \
112 value = sampler(data[pos], data[pos+1], frac); \
114 /* Direct path final mix buffer and panning */ \
115 value = lpFilter4P(DryFilter, 0, value); \
116 DryBuffer[j][FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
117 DryBuffer[j][FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
118 DryBuffer[j][SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
119 DryBuffer[j][SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
120 DryBuffer[j][BACK_LEFT] += value*DrySend[BACK_LEFT]; \
121 DryBuffer[j][BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
122 DryBuffer[j][FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
123 DryBuffer[j][BACK_CENTER] += value*DrySend[BACK_CENTER]; \
126 pos += frac>>FRACTIONBITS; \
127 frac &= FRACTIONMASK; \
130 if(j == SamplesToDo) \
136 ALuint64 pos64 = pos; \
137 pos64 <<= FRACTIONBITS; \
139 pos64 -= increment; \
140 p = pos64>>FRACTIONBITS; \
141 f = pos64&FRACTIONMASK; \
143 value = sampler(data[p], data[p+1], f); \
145 value = lpFilter4PC(DryFilter, 0, value); \
146 PendingClicks[FRONT_LEFT] += value*DrySend[FRONT_LEFT]; \
147 PendingClicks[FRONT_RIGHT] += value*DrySend[FRONT_RIGHT]; \
148 PendingClicks[SIDE_LEFT] += value*DrySend[SIDE_LEFT]; \
149 PendingClicks[SIDE_RIGHT] += value*DrySend[SIDE_RIGHT]; \
150 PendingClicks[BACK_LEFT] += value*DrySend[BACK_LEFT]; \
151 PendingClicks[BACK_RIGHT] += value*DrySend[BACK_RIGHT]; \
152 PendingClicks[FRONT_CENTER] += value*DrySend[FRONT_CENTER]; \
153 PendingClicks[BACK_CENTER] += value*DrySend[BACK_CENTER]; \
156 for(out = 0;out < Device->NumAuxSends;out++) \
159 ALfloat *WetBuffer; \
160 ALfloat *WetClickRemoval; \
161 ALfloat *WetPendingClicks; \
164 if(!Source->Send[out].Slot || \
165 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
168 WetBuffer = Source->Send[out].Slot->WetBuffer; \
169 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
170 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
171 WetFilter = &Source->Params.Send[out].iirFilter; \
172 WetSend = Source->Params.Send[out].WetGain; \
175 frac = DataPosFrac; \
180 value = sampler(data[pos], data[pos+1], frac); \
182 value = lpFilter2PC(WetFilter, 0, value); \
183 WetClickRemoval[0] -= value*WetSend; \
185 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
187 /* First order interpolator */ \
188 value = sampler(data[pos], data[pos+1], frac); \
190 /* Room path final mix buffer and panning */ \
191 value = lpFilter2P(WetFilter, 0, value); \
192 WetBuffer[j] += value*WetSend; \
195 pos += frac>>FRACTIONBITS; \
196 frac &= FRACTIONMASK; \
199 if(j == SamplesToDo) \
205 ALuint64 pos64 = pos; \
206 pos64 <<= FRACTIONBITS; \
208 pos64 -= increment; \
209 p = pos64>>FRACTIONBITS; \
210 f = pos64&FRACTIONMASK; \
212 value = sampler(data[p], data[p+1], f); \
214 value = lpFilter2PC(WetFilter, 0, value); \
215 WetPendingClicks[0] += value*WetSend; \
219 DataPosFrac = frac; \
222 #define DO_MIX_STEREO(data,sampler) do { \
223 const ALfloat scaler = 1.0f/Channels; \
224 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
225 ALfloat *ClickRemoval, *PendingClicks; \
227 ALfloat DrySend[OUTPUTCHANNELS]; \
233 DryBuffer = Device->DryBuffer; \
234 ClickRemoval = Device->ClickRemoval; \
235 PendingClicks = Device->PendingClicks; \
236 DryFilter = &Source->Params.iirFilter; \
237 for(i = 0;i < OUTPUTCHANNELS;i++) \
238 DrySend[i] = Source->Params.DryGains[i]; \
241 frac = DataPosFrac; \
245 for(i = 0;i < Channels;i++) \
247 value = sampler(data[pos*Channels + i], \
248 data[(pos+1)*Channels + i], frac); \
250 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
251 ClickRemoval[chans[i+0]] -= value*DrySend[chans[i+0]]; \
252 ClickRemoval[chans[i+2]] -= value*DrySend[chans[i+2]]; \
253 ClickRemoval[chans[i+4]] -= value*DrySend[chans[i+4]]; \
256 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
258 for(i = 0;i < Channels;i++) \
260 value = sampler(data[pos*Channels + i], \
261 data[(pos+1)*Channels + i], frac); \
263 value = lpFilter2P(DryFilter, chans[i]*2, value); \
264 DryBuffer[j][chans[i+0]] += value*DrySend[chans[i+0]]; \
265 DryBuffer[j][chans[i+2]] += value*DrySend[chans[i+2]]; \
266 DryBuffer[j][chans[i+4]] += value*DrySend[chans[i+4]]; \
270 pos += frac>>FRACTIONBITS; \
271 frac &= FRACTIONMASK; \
274 if(j == SamplesToDo) \
280 ALuint64 pos64 = pos; \
281 pos64 <<= FRACTIONBITS; \
283 pos64 -= increment; \
284 p = pos64>>FRACTIONBITS; \
285 f = pos64&FRACTIONMASK; \
287 for(i = 0;i < Channels;i++) \
289 value = sampler(data[p*Channels + i], \
290 data[(p+1)*Channels + i], f); \
292 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
293 PendingClicks[chans[i+0]] += value*DrySend[chans[i+0]]; \
294 PendingClicks[chans[i+2]] += value*DrySend[chans[i+2]]; \
295 PendingClicks[chans[i+4]] += value*DrySend[chans[i+4]]; \
299 for(out = 0;out < Device->NumAuxSends;out++) \
302 ALfloat *WetBuffer; \
303 ALfloat *WetClickRemoval; \
304 ALfloat *WetPendingClicks; \
307 if(!Source->Send[out].Slot || \
308 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
311 WetBuffer = Source->Send[out].Slot->WetBuffer; \
312 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
313 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
314 WetFilter = &Source->Params.Send[out].iirFilter; \
315 WetSend = Source->Params.Send[out].WetGain; \
318 frac = DataPosFrac; \
323 for(i = 0;i < Channels;i++) \
325 value = sampler(data[pos*Channels + i], \
326 data[(pos+1)*Channels + i], frac); \
328 value = lpFilter1PC(WetFilter, chans[i], value); \
329 WetClickRemoval[0] -= value*WetSend * scaler; \
332 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
334 for(i = 0;i < Channels;i++) \
336 value = sampler(data[pos*Channels + i], \
337 data[(pos+1)*Channels + i], frac); \
339 value = lpFilter1P(WetFilter, chans[i], value); \
340 WetBuffer[j] += value*WetSend * scaler; \
344 pos += frac>>FRACTIONBITS; \
345 frac &= FRACTIONMASK; \
348 if(j == SamplesToDo) \
354 ALuint64 pos64 = pos; \
355 pos64 <<= FRACTIONBITS; \
357 pos64 -= increment; \
358 p = pos64>>FRACTIONBITS; \
359 f = pos64&FRACTIONMASK; \
361 for(i = 0;i < Channels;i++) \
363 value = sampler(data[p*Channels + i], \
364 data[(p+1)*Channels + i], f); \
366 value = lpFilter1PC(WetFilter, chans[i], value); \
367 WetPendingClicks[0] += value*WetSend * scaler; \
372 DataPosFrac = frac; \
375 #define DO_MIX_MC(data,sampler) do { \
376 const ALfloat scaler = 1.0f/Channels; \
377 ALfloat (*DryBuffer)[OUTPUTCHANNELS]; \
378 ALfloat *ClickRemoval, *PendingClicks; \
380 ALfloat DrySend[OUTPUTCHANNELS]; \
386 DryBuffer = Device->DryBuffer; \
387 ClickRemoval = Device->ClickRemoval; \
388 PendingClicks = Device->PendingClicks; \
389 DryFilter = &Source->Params.iirFilter; \
390 for(i = 0;i < OUTPUTCHANNELS;i++) \
391 DrySend[i] = Source->Params.DryGains[i]; \
394 frac = DataPosFrac; \
398 for(i = 0;i < Channels;i++) \
400 value = sampler(data[pos*Channels + i], \
401 data[(pos+1)*Channels + i], frac); \
403 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
404 ClickRemoval[chans[i]] -= value*DrySend[chans[i]]; \
407 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
409 for(i = 0;i < Channels;i++) \
411 value = sampler(data[pos*Channels + i], \
412 data[(pos+1)*Channels + i], frac); \
414 value = lpFilter2P(DryFilter, chans[i]*2, value); \
415 DryBuffer[j][chans[i]] += value*DrySend[chans[i]]; \
419 pos += frac>>FRACTIONBITS; \
420 frac &= FRACTIONMASK; \
423 if(j == SamplesToDo) \
429 ALuint64 pos64 = pos; \
430 pos64 <<= FRACTIONBITS; \
432 pos64 -= increment; \
433 p = pos64>>FRACTIONBITS; \
434 f = pos64&FRACTIONMASK; \
436 for(i = 0;i < Channels;i++) \
438 value = sampler(data[p*Channels + i], \
439 data[(p+1)*Channels + i], f); \
441 value = lpFilter2PC(DryFilter, chans[i]*2, value); \
442 PendingClicks[chans[i]] += value*DrySend[chans[i]]; \
446 for(out = 0;out < Device->NumAuxSends;out++) \
449 ALfloat *WetBuffer; \
450 ALfloat *WetClickRemoval; \
451 ALfloat *WetPendingClicks; \
454 if(!Source->Send[out].Slot || \
455 Source->Send[out].Slot->effect.type == AL_EFFECT_NULL) \
458 WetBuffer = Source->Send[out].Slot->WetBuffer; \
459 WetClickRemoval = Source->Send[out].Slot->ClickRemoval; \
460 WetPendingClicks = Source->Send[out].Slot->PendingClicks; \
461 WetFilter = &Source->Params.Send[out].iirFilter; \
462 WetSend = Source->Params.Send[out].WetGain; \
465 frac = DataPosFrac; \
470 for(i = 0;i < Channels;i++) \
472 value = sampler(data[pos*Channels + i], \
473 data[(pos+1)*Channels + i], frac); \
475 value = lpFilter1PC(WetFilter, chans[i], value); \
476 WetClickRemoval[0] -= value*WetSend * scaler; \
479 for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \
481 for(i = 0;i < Channels;i++) \
483 value = sampler(data[pos*Channels + i], \
484 data[(pos+1)*Channels + i], frac); \
486 value = lpFilter1P(WetFilter, chans[i], value); \
487 WetBuffer[j] += value*WetSend * scaler; \
491 pos += frac>>FRACTIONBITS; \
492 frac &= FRACTIONMASK; \
495 if(j == SamplesToDo) \
501 ALuint64 pos64 = pos; \
502 pos64 <<= FRACTIONBITS; \
504 pos64 -= increment; \
505 p = pos64>>FRACTIONBITS; \
506 f = pos64&FRACTIONMASK; \
508 for(i = 0;i < Channels;i++) \
510 value = sampler(data[p*Channels + i], \
511 data[(p+1)*Channels + i], f); \
513 value = lpFilter1PC(WetFilter, chans[i], value); \
514 WetPendingClicks[0] += value*WetSend * scaler; \
519 DataPosFrac = frac; \
523 #define MIX_MONO(sampler) do { \
525 DO_MIX_MONO(Data.p32,sampler##32); \
526 else if(Bytes == 2) \
527 DO_MIX_MONO(Data.p16,sampler##16); \
530 #define MIX_STEREO(sampler) do { \
531 const int chans[] = { \
532 FRONT_LEFT, FRONT_RIGHT, \
533 SIDE_LEFT, SIDE_RIGHT, \
534 BACK_LEFT, BACK_RIGHT \
538 DO_MIX_STEREO(Data.p32,sampler##32); \
539 else if(Bytes == 2) \
540 DO_MIX_STEREO(Data.p16,sampler##16); \
543 #define MIX_MC(sampler,...) do { \
544 const int chans[] = { __VA_ARGS__ }; \
547 DO_MIX_MC(Data.p32,sampler##32); \
548 else if(Bytes == 2) \
549 DO_MIX_MC(Data.p16,sampler##16); \
553 #define MIX(sampler) do { \
559 case 2: /* Stereo */ \
560 MIX_STEREO(sampler); \
563 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
564 BACK_LEFT, BACK_RIGHT); \
567 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
569 BACK_LEFT, BACK_RIGHT); \
572 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
575 SIDE_LEFT, SIDE_RIGHT); \
578 MIX_MC(sampler, FRONT_LEFT, FRONT_RIGHT, \
580 BACK_LEFT, BACK_RIGHT, \
581 SIDE_LEFT, SIDE_RIGHT); \
587 ALvoid
MixSource(ALsource
*Source
, ALCdevice
*Device
, ALuint SamplesToDo
)
589 ALbufferlistitem
*BufferListItem
;
590 ALint64 DataSize64
,DataPos64
;
592 ALuint DataPosInt
, DataPosFrac
;
593 ALuint BuffersPlayed
;
598 /* Get source info */
599 State
= Source
->state
;
600 BuffersPlayed
= Source
->BuffersPlayed
;
601 DataPosInt
= Source
->position
;
602 DataPosFrac
= Source
->position_fraction
;
603 Looping
= Source
->bLooping
;
605 /* Get current buffer queue item */
606 BufferListItem
= Source
->queue
;
607 for(i
= 0;i
< BuffersPlayed
;i
++)
608 BufferListItem
= BufferListItem
->next
;
612 const ALbuffer
*ALBuffer
;
619 ALuint LoopStart
= 0;
621 ALuint Channels
, Bytes
;
624 /* Get buffer info */
625 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
627 Data
.p8
= ALBuffer
->data
;
628 DataSize
= ALBuffer
->size
;
629 DataSize
/= aluFrameSizeFromFormat(ALBuffer
->format
);
630 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
631 Bytes
= aluBytesFromFormat(ALBuffer
->format
);
635 if(Looping
&& Source
->lSourceType
== AL_STATIC
)
637 /* If current pos is beyond the loop range, do not loop */
638 if(DataPosInt
>= LoopEnd
)
642 LoopStart
= ALBuffer
->LoopStart
;
643 LoopEnd
= ALBuffer
->LoopEnd
;
648 if(DataPosInt
>= DataSize
)
651 memset(&Data
.p8
[DataSize
*Channels
*Bytes
], 0, BUFFER_PADDING
*Channels
*Bytes
);
652 if(BufferListItem
->next
)
654 ALbuffer
*NextBuf
= BufferListItem
->next
->buffer
;
655 if(NextBuf
&& NextBuf
->size
)
657 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
658 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
659 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
660 NextBuf
->data
, ulExtraSamples
);
665 ALbuffer
*NextBuf
= Source
->queue
->buffer
;
666 if(NextBuf
&& NextBuf
->size
)
668 ALint ulExtraSamples
= BUFFER_PADDING
*Channels
*Bytes
;
669 ulExtraSamples
= min(NextBuf
->size
, ulExtraSamples
);
670 memcpy(&Data
.p8
[DataSize
*Channels
*Bytes
],
671 &((ALubyte
*)NextBuf
->data
)[LoopStart
*Channels
*Bytes
],
676 /* Figure out how many samples we can mix. */
677 increment
= Source
->Params
.Step
;
678 DataSize64
= LoopEnd
;
679 DataSize64
<<= FRACTIONBITS
;
680 DataPos64
= DataPosInt
;
681 DataPos64
<<= FRACTIONBITS
;
682 DataPos64
+= DataPosFrac
;
683 BufferSize
= (ALuint
)((DataSize64
-DataPos64
+(increment
-1)) / increment
);
685 BufferSize
= min(BufferSize
, (SamplesToDo
-j
));
687 switch(Source
->Resampler
)
689 case POINT_RESAMPLER
:
691 case LINEAR_RESAMPLER
:
693 case COSINE_RESAMPLER
:
694 MIX(cos_lerp
); break;
701 /* Handle looping sources */
702 if(DataPosInt
>= LoopEnd
)
704 if(BufferListItem
->next
)
706 BufferListItem
= BufferListItem
->next
;
708 DataPosInt
-= DataSize
;
712 BufferListItem
= Source
->queue
;
714 if(Source
->lSourceType
== AL_STATIC
)
715 DataPosInt
= ((DataPosInt
-LoopStart
)%(LoopEnd
-LoopStart
)) + LoopStart
;
717 DataPosInt
-= DataSize
;
722 BufferListItem
= Source
->queue
;
723 BuffersPlayed
= Source
->BuffersInQueue
;
728 } while(State
== AL_PLAYING
&& j
< SamplesToDo
);
730 /* Update source info */
731 Source
->state
= State
;
732 Source
->BuffersPlayed
= BuffersPlayed
;
733 Source
->position
= DataPosInt
;
734 Source
->position_fraction
= DataPosFrac
;
735 Source
->Buffer
= BufferListItem
->buffer
;