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"
46 ALfloat ConeScale
= 1.0f
;
48 /* Localized Z scalar for mono sources */
49 ALfloat ZScale
= 1.0f
;
52 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
55 vector
[0], vector
[1], vector
[2], w
58 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
59 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
60 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
64 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
66 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
67 static const struct ChanMap StereoMap
[2] = {
68 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
69 { FrontRight
, 30.0f
* F_PI
/180.0f
}
71 static const struct ChanMap StereoWideMap
[2] = {
72 { FrontLeft
, -90.0f
* F_PI
/180.0f
},
73 { FrontRight
, 90.0f
* F_PI
/180.0f
}
75 static const struct ChanMap RearMap
[2] = {
76 { BackLeft
, -150.0f
* F_PI
/180.0f
},
77 { BackRight
, 150.0f
* F_PI
/180.0f
}
79 static const struct ChanMap QuadMap
[4] = {
80 { FrontLeft
, -45.0f
* F_PI
/180.0f
},
81 { FrontRight
, 45.0f
* F_PI
/180.0f
},
82 { BackLeft
, -135.0f
* F_PI
/180.0f
},
83 { BackRight
, 135.0f
* F_PI
/180.0f
}
85 static const struct ChanMap X51Map
[6] = {
86 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
87 { FrontRight
, 30.0f
* F_PI
/180.0f
},
88 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
90 { BackLeft
, -110.0f
* F_PI
/180.0f
},
91 { BackRight
, 110.0f
* F_PI
/180.0f
}
93 static const struct ChanMap X61Map
[7] = {
94 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
95 { FrontRight
, 30.0f
* F_PI
/180.0f
},
96 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
98 { BackCenter
, 180.0f
* F_PI
/180.0f
},
99 { SideLeft
, -90.0f
* F_PI
/180.0f
},
100 { SideRight
, 90.0f
* F_PI
/180.0f
}
102 static const struct ChanMap X71Map
[8] = {
103 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
104 { FrontRight
, 30.0f
* F_PI
/180.0f
},
105 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
107 { BackLeft
, -150.0f
* F_PI
/180.0f
},
108 { BackRight
, 150.0f
* F_PI
/180.0f
},
109 { SideLeft
, -90.0f
* F_PI
/180.0f
},
110 { SideRight
, 90.0f
* F_PI
/180.0f
}
113 ALCdevice
*Device
= ALContext
->Device
;
114 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
115 ALbufferlistitem
*BufferListItem
;
116 enum FmtChannels Channels
;
117 ALfloat (*SrcMatrix
)[MaxChannels
];
118 ALfloat DryGain
, DryGainHF
;
119 ALfloat WetGain
[MAX_SENDS
];
120 ALfloat WetGainHF
[MAX_SENDS
];
121 ALint NumSends
, Frequency
;
122 const struct ChanMap
*chans
= NULL
;
123 enum Resampler Resampler
;
124 ALint num_channels
= 0;
125 ALboolean DirectChannels
;
126 ALfloat hwidth
= 0.0f
;
131 /* Get device properties */
132 NumSends
= Device
->NumAuxSends
;
133 Frequency
= Device
->Frequency
;
135 /* Get listener properties */
136 ListenerGain
= ALContext
->Listener
.Gain
;
138 /* Get source properties */
139 SourceVolume
= ALSource
->Gain
;
140 MinVolume
= ALSource
->MinGain
;
141 MaxVolume
= ALSource
->MaxGain
;
142 Pitch
= ALSource
->Pitch
;
143 Resampler
= ALSource
->Resampler
;
144 DirectChannels
= ALSource
->DirectChannels
;
146 /* Calculate the stepping value */
148 BufferListItem
= ALSource
->queue
;
149 while(BufferListItem
!= NULL
)
152 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
154 ALsizei maxstep
= STACK_DATA_SIZE
/sizeof(ALfloat
) /
155 ALSource
->NumChannels
;
156 maxstep
-= ResamplerPadding
[Resampler
] +
157 ResamplerPrePadding
[Resampler
] + 1;
158 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
160 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
161 if(Pitch
> (ALfloat
)maxstep
)
162 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
165 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
166 if(ALSource
->Params
.Step
== 0)
167 ALSource
->Params
.Step
= 1;
169 if(ALSource
->Params
.Step
== FRACTIONONE
)
170 Resampler
= PointResampler
;
172 Channels
= ALBuffer
->FmtChannels
;
175 BufferListItem
= BufferListItem
->next
;
177 if(!DirectChannels
&& Device
->Hrtf
)
178 ALSource
->Params
.DryMix
= SelectHrtfMixer(Resampler
);
180 ALSource
->Params
.DryMix
= SelectDirectMixer(Resampler
);
181 ALSource
->Params
.WetMix
= SelectSendMixer(Resampler
);
183 /* Calculate gains */
184 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
185 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
186 DryGainHF
= ALSource
->DirectGainHF
;
187 for(i
= 0;i
< NumSends
;i
++)
189 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
190 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
191 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
194 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
195 for(i
= 0;i
< MaxChannels
;i
++)
197 for(c
= 0;c
< MaxChannels
;c
++)
198 SrcMatrix
[i
][c
] = 0.0f
;
208 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
212 chans
= StereoWideMap
;
213 hwidth
= 60.0f
* F_PI
/180.0f
;
244 if(DirectChannels
!= AL_FALSE
)
246 for(c
= 0;c
< num_channels
;c
++)
248 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
250 enum Channel chan
= Device
->Speaker2Chan
[i
];
251 if(chan
== chans
[c
].channel
)
253 SrcMatrix
[c
][chan
] += DryGain
;
259 else if(Device
->Hrtf
)
261 for(c
= 0;c
< num_channels
;c
++)
263 if(chans
[c
].channel
== LFE
)
266 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][0] = 0;
267 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][1] = 0;
268 for(i
= 0;i
< HRIR_LENGTH
;i
++)
270 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][0] = 0.0f
;
271 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][1] = 0.0f
;
276 /* Get the static HRIR coefficients and delays for this
278 GetLerpedHrtfCoeffs(Device
->Hrtf
,
279 0.0f
, chans
[c
].angle
, DryGain
,
280 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
],
281 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
]);
284 ALSource
->Hrtf
.Counter
= 0;
288 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf(Device
->NumChan
), hwidth
/(F_PI
*2.0f
));
289 for(c
= 0;c
< num_channels
;c
++)
291 /* Special-case LFE */
292 if(chans
[c
].channel
== LFE
)
294 SrcMatrix
[c
][chans
[c
].channel
] = DryGain
;
297 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
301 for(i
= 0;i
< NumSends
;i
++)
303 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
306 Slot
= Device
->DefaultSlot
;
307 if(Slot
&& Slot
->effect
.type
== AL_EFFECT_NULL
)
309 ALSource
->Params
.Slot
[i
] = Slot
;
310 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
313 /* Update filter coefficients. Calculations based on the I3DL2
315 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
317 /* We use two chained one-pole filters, so we need to take the
318 * square root of the squared gain, which is the same as the base
320 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
321 for(i
= 0;i
< NumSends
;i
++)
323 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
324 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
328 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
330 const ALCdevice
*Device
= ALContext
->Device
;
331 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
332 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
333 ALfloat Velocity
[3],ListenerVel
[3];
334 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
335 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
336 ALfloat DopplerFactor
, SpeedOfSound
;
337 ALfloat AirAbsorptionFactor
;
338 ALfloat RoomAirAbsorption
[MAX_SENDS
];
339 ALbufferlistitem
*BufferListItem
;
341 ALfloat RoomAttenuation
[MAX_SENDS
];
342 ALfloat MetersPerUnit
;
343 ALfloat RoomRolloffBase
;
344 ALfloat RoomRolloff
[MAX_SENDS
];
345 ALfloat DecayDistance
[MAX_SENDS
];
348 ALboolean DryGainHFAuto
;
349 ALfloat WetGain
[MAX_SENDS
];
350 ALfloat WetGainHF
[MAX_SENDS
];
351 ALboolean WetGainAuto
;
352 ALboolean WetGainHFAuto
;
353 enum Resampler Resampler
;
354 ALfloat Matrix
[4][4];
362 for(i
= 0;i
< MAX_SENDS
;i
++)
365 /* Get context/device properties */
366 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
367 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
368 NumSends
= Device
->NumAuxSends
;
369 Frequency
= Device
->Frequency
;
371 /* Get listener properties */
372 ListenerGain
= ALContext
->Listener
.Gain
;
373 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
374 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
375 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
376 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
380 Matrix
[i
][j
] = ALContext
->Listener
.Matrix
[i
][j
];
383 /* Get source properties */
384 SourceVolume
= ALSource
->Gain
;
385 MinVolume
= ALSource
->MinGain
;
386 MaxVolume
= ALSource
->MaxGain
;
387 Pitch
= ALSource
->Pitch
;
388 Resampler
= ALSource
->Resampler
;
389 Position
[0] = ALSource
->Position
[0];
390 Position
[1] = ALSource
->Position
[1];
391 Position
[2] = ALSource
->Position
[2];
392 Direction
[0] = ALSource
->Orientation
[0];
393 Direction
[1] = ALSource
->Orientation
[1];
394 Direction
[2] = ALSource
->Orientation
[2];
395 Velocity
[0] = ALSource
->Velocity
[0];
396 Velocity
[1] = ALSource
->Velocity
[1];
397 Velocity
[2] = ALSource
->Velocity
[2];
398 MinDist
= ALSource
->RefDistance
;
399 MaxDist
= ALSource
->MaxDistance
;
400 Rolloff
= ALSource
->RollOffFactor
;
401 InnerAngle
= ALSource
->InnerAngle
;
402 OuterAngle
= ALSource
->OuterAngle
;
403 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
404 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
405 WetGainAuto
= ALSource
->WetGainAuto
;
406 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
407 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
408 for(i
= 0;i
< NumSends
;i
++)
410 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
413 Slot
= Device
->DefaultSlot
;
414 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
417 RoomRolloff
[i
] = 0.0f
;
418 DecayDistance
[i
] = 0.0f
;
419 RoomAirAbsorption
[i
] = 1.0f
;
421 else if(Slot
->AuxSendAuto
)
423 RoomRolloff
[i
] = RoomRolloffBase
;
424 if(IsReverbEffect(Slot
->effect
.type
))
426 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
427 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
428 SPEEDOFSOUNDMETRESPERSEC
;
429 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
433 DecayDistance
[i
] = 0.0f
;
434 RoomAirAbsorption
[i
] = 1.0f
;
439 /* If the slot's auxiliary send auto is off, the data sent to the
440 * effect slot is the same as the dry path, sans filter effects */
441 RoomRolloff
[i
] = Rolloff
;
442 DecayDistance
[i
] = 0.0f
;
443 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
446 ALSource
->Params
.Slot
[i
] = Slot
;
449 /* Transform source to listener space (convert to head relative) */
450 if(ALSource
->HeadRelative
== AL_FALSE
)
452 /* Translate position */
453 Position
[0] -= ALContext
->Listener
.Position
[0];
454 Position
[1] -= ALContext
->Listener
.Position
[1];
455 Position
[2] -= ALContext
->Listener
.Position
[2];
457 /* Transform source vectors */
458 aluMatrixVector(Position
, 1.0f
, Matrix
);
459 aluMatrixVector(Direction
, 0.0f
, Matrix
);
460 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
461 /* Transform listener velocity */
462 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
466 /* Transform listener velocity from world space to listener space */
467 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
468 /* Offset the source velocity to be relative of the listener velocity */
469 Velocity
[0] += ListenerVel
[0];
470 Velocity
[1] += ListenerVel
[1];
471 Velocity
[2] += ListenerVel
[2];
474 SourceToListener
[0] = -Position
[0];
475 SourceToListener
[1] = -Position
[1];
476 SourceToListener
[2] = -Position
[2];
477 aluNormalize(SourceToListener
);
478 aluNormalize(Direction
);
480 /* Calculate distance attenuation */
481 Distance
= sqrtf(aluDotproduct(Position
, Position
));
482 ClampedDist
= Distance
;
485 for(i
= 0;i
< NumSends
;i
++)
486 RoomAttenuation
[i
] = 1.0f
;
487 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
488 ALContext
->DistanceModel
)
490 case InverseDistanceClamped
:
491 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
492 if(MaxDist
< MinDist
)
495 case InverseDistance
:
498 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
499 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
500 for(i
= 0;i
< NumSends
;i
++)
502 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
503 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
508 case LinearDistanceClamped
:
509 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
510 if(MaxDist
< MinDist
)
514 if(MaxDist
!= MinDist
)
516 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
517 Attenuation
= maxf(Attenuation
, 0.0f
);
518 for(i
= 0;i
< NumSends
;i
++)
520 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
521 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
526 case ExponentDistanceClamped
:
527 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
528 if(MaxDist
< MinDist
)
531 case ExponentDistance
:
532 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
534 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
535 for(i
= 0;i
< NumSends
;i
++)
536 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
540 case DisableDistance
:
541 ClampedDist
= MinDist
;
545 /* Source Gain + Attenuation */
546 DryGain
= SourceVolume
* Attenuation
;
547 for(i
= 0;i
< NumSends
;i
++)
548 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
550 /* Distance-based air absorption */
551 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
553 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
554 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
555 for(i
= 0;i
< NumSends
;i
++)
556 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
561 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
563 /* Apply a decay-time transformation to the wet path, based on the
564 * attenuation of the dry path.
566 * Using the apparent distance, based on the distance attenuation, the
567 * initial decay of the reverb effect is calculated and applied to the
570 for(i
= 0;i
< NumSends
;i
++)
572 if(DecayDistance
[i
] > 0.0f
)
573 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
577 /* Calculate directional soundcones */
578 Angle
= acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
* (360.0f
/F_PI
);
579 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
581 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
582 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
583 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
585 else if(Angle
> OuterAngle
)
587 ConeVolume
= ALSource
->OuterGain
;
588 ConeHF
= ALSource
->OuterGainHF
;
596 DryGain
*= ConeVolume
;
599 for(i
= 0;i
< NumSends
;i
++)
600 WetGain
[i
] *= ConeVolume
;
606 for(i
= 0;i
< NumSends
;i
++)
607 WetGainHF
[i
] *= ConeHF
;
610 /* Clamp to Min/Max Gain */
611 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
612 for(i
= 0;i
< NumSends
;i
++)
613 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
615 /* Apply gain and frequency filters */
616 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
617 DryGainHF
*= ALSource
->DirectGainHF
;
618 for(i
= 0;i
< NumSends
;i
++)
620 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
621 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
624 /* Calculate velocity-based doppler effect */
625 if(DopplerFactor
> 0.0f
)
629 if(SpeedOfSound
< 1.0f
)
631 DopplerFactor
*= 1.0f
/SpeedOfSound
;
635 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
636 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
638 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
639 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
642 BufferListItem
= ALSource
->queue
;
643 while(BufferListItem
!= NULL
)
646 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
648 /* Calculate fixed-point stepping value, based on the pitch, buffer
649 * frequency, and output frequency. */
650 ALsizei maxstep
= STACK_DATA_SIZE
/sizeof(ALfloat
) /
651 ALSource
->NumChannels
;
652 maxstep
-= ResamplerPadding
[Resampler
] +
653 ResamplerPrePadding
[Resampler
] + 1;
654 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
656 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
657 if(Pitch
> (ALfloat
)maxstep
)
658 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
661 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
662 if(ALSource
->Params
.Step
== 0)
663 ALSource
->Params
.Step
= 1;
665 if(ALSource
->Params
.Step
== FRACTIONONE
)
666 Resampler
= PointResampler
;
670 BufferListItem
= BufferListItem
->next
;
673 ALSource
->Params
.DryMix
= SelectHrtfMixer(Resampler
);
675 ALSource
->Params
.DryMix
= SelectDirectMixer(Resampler
);
676 ALSource
->Params
.WetMix
= SelectSendMixer(Resampler
);
680 /* Use a binaural HRTF algorithm for stereo headphone playback */
681 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
685 ALfloat invlen
= 1.0f
/Distance
;
686 Position
[0] *= invlen
;
687 Position
[1] *= invlen
;
688 Position
[2] *= invlen
;
690 /* Calculate elevation and azimuth only when the source is not at
691 * the listener. This prevents +0 and -0 Z from producing
692 * inconsistent panning. Also, clamp Y in case FP precision errors
693 * cause it to land outside of -1..+1. */
694 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
695 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
698 /* Check to see if the HRIR is already moving. */
699 if(ALSource
->Hrtf
.Moving
)
701 /* Calculate the normalized HRTF transition factor (delta). */
702 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Gain
, DryGain
,
703 ALSource
->Params
.Direct
.Hrtf
.Dir
, Position
);
704 /* If the delta is large enough, get the moving HRIR target
705 * coefficients, target delays, steppping values, and counter. */
708 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
709 ev
, az
, DryGain
, delta
,
710 ALSource
->Hrtf
.Counter
,
711 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
712 ALSource
->Params
.Direct
.Hrtf
.Delay
[0],
713 ALSource
->Params
.Direct
.Hrtf
.CoeffStep
,
714 ALSource
->Params
.Direct
.Hrtf
.DelayStep
);
715 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
716 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
717 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
718 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
723 /* Get the initial (static) HRIR coefficients and delays. */
724 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
725 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
726 ALSource
->Params
.Direct
.Hrtf
.Delay
[0]);
727 ALSource
->Hrtf
.Counter
= 0;
728 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
729 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
730 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
731 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
736 ALfloat (*Matrix
)[MaxChannels
] = ALSource
->Params
.Direct
.Gains
;
737 ALfloat DirGain
= 0.0f
;
740 for(i
= 0;i
< MaxChannels
;i
++)
742 for(j
= 0;j
< MaxChannels
;j
++)
746 /* Normalize the length, and compute panned gains. */
749 ALfloat invlen
= 1.0f
/Distance
;
750 Position
[0] *= invlen
;
751 Position
[1] *= invlen
;
752 Position
[2] *= invlen
;
754 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
755 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
756 DryGain
*DirGain
, Matrix
[0]);
759 /* Adjustment for vertical offsets. Not the greatest, but simple
761 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
762 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
764 enum Channel chan
= Device
->Speaker2Chan
[i
];
765 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
768 for(i
= 0;i
< NumSends
;i
++)
769 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
771 /* Update filter coefficients. */
772 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
774 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
775 for(i
= 0;i
< NumSends
;i
++)
777 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
778 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
783 static __inline ALfloat
aluF2F(ALfloat val
)
785 static __inline ALint
aluF2I(ALfloat val
)
787 if(val
> 1.0f
) return 2147483647;
788 if(val
< -1.0f
) return -2147483647-1;
789 return fastf2i((ALfloat
)(val
*2147483647.0));
791 static __inline ALuint
aluF2UI(ALfloat val
)
792 { return aluF2I(val
)+2147483648u; }
793 static __inline ALshort
aluF2S(ALfloat val
)
794 { return aluF2I(val
)>>16; }
795 static __inline ALushort
aluF2US(ALfloat val
)
796 { return aluF2S(val
)+32768; }
797 static __inline ALbyte
aluF2B(ALfloat val
)
798 { return aluF2I(val
)>>24; }
799 static __inline ALubyte
aluF2UB(ALfloat val
)
800 { return aluF2B(val
)+128; }
802 #define DECL_TEMPLATE(T, N, func) \
803 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
804 ALuint SamplesToDo) \
806 ALfloat (*RESTRICT DryBuffer)[MaxChannels] = device->DryBuffer; \
807 const enum Channel *ChanMap = device->DevChannels; \
810 for(j = 0;j < N;j++) \
812 T *RESTRICT out = buffer + j; \
813 enum Channel chan = ChanMap[j]; \
815 for(i = 0;i < SamplesToDo;i++) \
816 out[i*N] = func(DryBuffer[i][chan]); \
820 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
821 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
822 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
823 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
824 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
825 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
827 DECL_TEMPLATE(ALuint
, 1, aluF2UI
)
828 DECL_TEMPLATE(ALuint
, 2, aluF2UI
)
829 DECL_TEMPLATE(ALuint
, 4, aluF2UI
)
830 DECL_TEMPLATE(ALuint
, 6, aluF2UI
)
831 DECL_TEMPLATE(ALuint
, 7, aluF2UI
)
832 DECL_TEMPLATE(ALuint
, 8, aluF2UI
)
834 DECL_TEMPLATE(ALint
, 1, aluF2I
)
835 DECL_TEMPLATE(ALint
, 2, aluF2I
)
836 DECL_TEMPLATE(ALint
, 4, aluF2I
)
837 DECL_TEMPLATE(ALint
, 6, aluF2I
)
838 DECL_TEMPLATE(ALint
, 7, aluF2I
)
839 DECL_TEMPLATE(ALint
, 8, aluF2I
)
841 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
842 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
843 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
844 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
845 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
846 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
848 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
849 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
850 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
851 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
852 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
853 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
855 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
856 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
857 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
858 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
859 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
860 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
862 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
863 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
864 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
865 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
866 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
867 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
871 #define DECL_TEMPLATE(T) \
872 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
874 switch(device->FmtChans) \
877 Write_##T##_1(device, buffer, SamplesToDo); \
880 Write_##T##_2(device, buffer, SamplesToDo); \
883 Write_##T##_4(device, buffer, SamplesToDo); \
886 case DevFmtX51Side: \
887 Write_##T##_6(device, buffer, SamplesToDo); \
890 Write_##T##_7(device, buffer, SamplesToDo); \
893 Write_##T##_8(device, buffer, SamplesToDo); \
898 DECL_TEMPLATE(ALfloat
)
899 DECL_TEMPLATE(ALuint
)
901 DECL_TEMPLATE(ALushort
)
902 DECL_TEMPLATE(ALshort
)
903 DECL_TEMPLATE(ALubyte
)
904 DECL_TEMPLATE(ALbyte
)
908 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
911 ALeffectslot
**slot
, **slot_end
;
912 ALsource
**src
, **src_end
;
917 fpuState
= SetMixerFPUMode();
921 SamplesToDo
= minu(size
, BUFFERSIZE
);
922 memset(device
->DryBuffer
, 0, SamplesToDo
*MaxChannels
*sizeof(ALfloat
));
925 ctx
= device
->ContextList
;
928 ALenum DeferUpdates
= ctx
->DeferUpdates
;
929 ALenum UpdateSources
= AL_FALSE
;
932 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
934 /* source processing */
935 src
= ctx
->ActiveSources
;
936 src_end
= src
+ ctx
->ActiveSourceCount
;
937 while(src
!= src_end
)
939 if((*src
)->state
!= AL_PLAYING
)
941 --(ctx
->ActiveSourceCount
);
946 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
948 ALsource_Update(*src
, ctx
);
950 MixSource(*src
, device
, SamplesToDo
);
954 /* effect slot processing */
955 slot
= ctx
->ActiveEffectSlots
;
956 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
957 while(slot
!= slot_end
)
959 for(c
= 0;c
< SamplesToDo
;c
++)
961 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
962 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
964 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
965 (*slot
)->PendingClicks
[0] = 0.0f
;
967 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
968 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
970 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
971 (*slot
)->WetBuffer
, device
->DryBuffer
);
973 for(i
= 0;i
< SamplesToDo
;i
++)
974 (*slot
)->WetBuffer
[i
] = 0.0f
;
982 slot
= &device
->DefaultSlot
;
985 for(c
= 0;c
< SamplesToDo
;c
++)
987 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
988 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
990 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
991 (*slot
)->PendingClicks
[0] = 0.0f
;
993 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
994 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
996 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
997 (*slot
)->WetBuffer
, device
->DryBuffer
);
999 for(i
= 0;i
< SamplesToDo
;i
++)
1000 (*slot
)->WetBuffer
[i
] = 0.0f
;
1002 UnlockDevice(device
);
1004 /* Click-removal. Could do better; this only really handles immediate
1005 * changes between updates where a predictive sample could be
1006 * generated. Delays caused by effects and HRTF aren't caught. */
1007 if(device
->FmtChans
== DevFmtMono
)
1009 for(i
= 0;i
< SamplesToDo
;i
++)
1011 device
->DryBuffer
[i
][FrontCenter
] += device
->ClickRemoval
[FrontCenter
];
1012 device
->ClickRemoval
[FrontCenter
] -= device
->ClickRemoval
[FrontCenter
] * (1.0f
/256.0f
);
1014 device
->ClickRemoval
[FrontCenter
] += device
->PendingClicks
[FrontCenter
];
1015 device
->PendingClicks
[FrontCenter
] = 0.0f
;
1017 else if(device
->FmtChans
== DevFmtStereo
)
1019 /* Assumes the first two channels are FrontLeft and FrontRight */
1020 for(i
= 0;i
< SamplesToDo
;i
++)
1022 for(c
= 0;c
< 2;c
++)
1024 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1025 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1028 for(c
= 0;c
< 2;c
++)
1030 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1031 device
->PendingClicks
[c
] = 0.0f
;
1035 for(i
= 0;i
< SamplesToDo
;i
++)
1036 bs2b_cross_feed(device
->Bs2b
, &device
->DryBuffer
[i
][0]);
1041 for(i
= 0;i
< SamplesToDo
;i
++)
1043 for(c
= 0;c
< MaxChannels
;c
++)
1045 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1046 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1049 for(c
= 0;c
< MaxChannels
;c
++)
1051 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1052 device
->PendingClicks
[c
] = 0.0f
;
1058 switch(device
->FmtType
)
1061 Write_ALbyte(device
, buffer
, SamplesToDo
);
1064 Write_ALubyte(device
, buffer
, SamplesToDo
);
1067 Write_ALshort(device
, buffer
, SamplesToDo
);
1070 Write_ALushort(device
, buffer
, SamplesToDo
);
1073 Write_ALint(device
, buffer
, SamplesToDo
);
1076 Write_ALuint(device
, buffer
, SamplesToDo
);
1079 Write_ALfloat(device
, buffer
, SamplesToDo
);
1084 size
-= SamplesToDo
;
1087 RestoreFPUMode(fpuState
);
1091 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1093 ALCcontext
*Context
;
1096 device
->Connected
= ALC_FALSE
;
1098 Context
= device
->ContextList
;
1101 ALsource
**src
, **src_end
;
1103 src
= Context
->ActiveSources
;
1104 src_end
= src
+ Context
->ActiveSourceCount
;
1105 while(src
!= src_end
)
1107 if((*src
)->state
== AL_PLAYING
)
1109 (*src
)->state
= AL_STOPPED
;
1110 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1111 (*src
)->position
= 0;
1112 (*src
)->position_fraction
= 0;
1116 Context
->ActiveSourceCount
= 0;
1118 Context
= Context
->next
;
1120 UnlockDevice(device
);