Add a method to calculate gains given a sound point and its half-width, and use it for reverb
The half-width ranges from 0 to pi, and essentially specifies the coverage area around the listener. At 0, it's an infinitely small point sound and behaves like a usual panning sound. At pi/2 it covers half the area, and at pi it covers the whole area.
This commit is contained in:
+10
-32
@@ -1016,20 +1016,17 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
|
||||
ReflectionsPan[2] };
|
||||
ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
|
||||
LateReverbPan[2] };
|
||||
const ALfloat *ChannelGain;
|
||||
ALfloat ambientGain;
|
||||
ALfloat dirGain;
|
||||
ALfloat length;
|
||||
ALuint index;
|
||||
ALint pos;
|
||||
|
||||
Gain *= ReverbBoost;
|
||||
|
||||
// Attenuate non-directional reverb according to the number of channels
|
||||
ambientGain = aluSqrt(2.0f/Device->NumChan);
|
||||
/* Attenuate reverb according to its coverage (dirGain=0 will give
|
||||
* Gain*ambientGain, and dirGain=1 will give Gain). */
|
||||
ambientGain = minf(aluSqrt(2.0f/Device->NumChan), 1.0f);
|
||||
|
||||
// Calculate the 3D-panning gains for the early reflections and late
|
||||
// reverb.
|
||||
length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
|
||||
if(length > 1.0f)
|
||||
{
|
||||
@@ -1047,36 +1044,17 @@ static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *Reflection
|
||||
latePan[2] *= length;
|
||||
}
|
||||
|
||||
/* This code applies directional reverb just like the mixer applies
|
||||
* directional sources. It diffuses the sound toward all speakers as the
|
||||
* magnitude of the panning vector drops, which is only a rough
|
||||
* approximation of the expansion of sound across the speakers from the
|
||||
* panning direction.
|
||||
*/
|
||||
pos = aluCart2LUTpos(earlyPan[0], earlyPan[2]);
|
||||
ChannelGain = Device->PanningLUT[pos];
|
||||
dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
|
||||
|
||||
dirGain = aluSqrt(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]);
|
||||
for(index = 0;index < MAXCHANNELS;index++)
|
||||
State->Early.PanGain[index] = 0.0f;
|
||||
for(index = 0;index < Device->NumChan;index++)
|
||||
{
|
||||
enum Channel chan = Device->Speaker2Chan[index];
|
||||
State->Early.PanGain[chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * Gain;
|
||||
}
|
||||
|
||||
|
||||
pos = aluCart2LUTpos(latePan[0], latePan[2]);
|
||||
ChannelGain = Device->PanningLUT[pos];
|
||||
dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
|
||||
State->Early.PanGain[index] = 0.0f;
|
||||
ComputeAngleGains(Device, aluAtan2(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI,
|
||||
lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain);
|
||||
|
||||
dirGain = aluSqrt(latePan[0]*latePan[0] + latePan[2]*latePan[2]);
|
||||
for(index = 0;index < MAXCHANNELS;index++)
|
||||
State->Late.PanGain[index] = 0.0f;
|
||||
for(index = 0;index < Device->NumChan;index++)
|
||||
{
|
||||
enum Channel chan = Device->Speaker2Chan[index];
|
||||
State->Late.PanGain[chan] = lerp(ambientGain, ChannelGain[chan], dirGain) * Gain;
|
||||
}
|
||||
ComputeAngleGains(Device, aluAtan2(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI,
|
||||
lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain);
|
||||
}
|
||||
|
||||
// This updates the EAX reverb state. This is called any time the EAX reverb
|
||||
|
||||
+161
@@ -164,6 +164,167 @@ ALint aluCart2LUTpos(ALfloat im, ALfloat re)
|
||||
return pos%LUT_NUM;
|
||||
}
|
||||
|
||||
/**
|
||||
* ComputeAngleGains
|
||||
*
|
||||
* Sets channel gains based on a given source's angle and its half-width. The
|
||||
* angle and hwidth parameters are in radians.
|
||||
*/
|
||||
ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains)
|
||||
{
|
||||
const enum Channel *Speaker2Chan = device->Speaker2Chan;
|
||||
const ALfloat *SpeakerAngle = device->SpeakerAngle;
|
||||
ALfloat tmpgains[MAXCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
ALboolean inverted = AL_FALSE;
|
||||
ALfloat langle, rangle;
|
||||
ALfloat a;
|
||||
ALuint i;
|
||||
|
||||
/* Some easy special-cases first... */
|
||||
if(device->NumChan == 1 || hwidth >= F_PI)
|
||||
{
|
||||
/* Full coverage for all speakers. */
|
||||
for(i = 0;i < device->NumChan;i++)
|
||||
{
|
||||
enum Channel chan = Speaker2Chan[i];
|
||||
gains[chan] = ingain;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(hwidth <= 0.0f)
|
||||
{
|
||||
/* Infinitismally small sound point. */
|
||||
for(i = 0;i < device->NumChan-1;i++)
|
||||
{
|
||||
if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
|
||||
{
|
||||
/* Sound is between speaker i and i+1 */
|
||||
a = (angle-SpeakerAngle[i]) /
|
||||
(SpeakerAngle[i+1]-SpeakerAngle[i]);
|
||||
gains[Speaker2Chan[i]] = aluSqrt(1.0f-a) * ingain;
|
||||
gains[Speaker2Chan[i+1]] = aluSqrt( a) * ingain;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Sound is between last and first speakers */
|
||||
if(angle < SpeakerAngle[0])
|
||||
angle += F_PI*2.0f;
|
||||
a = (angle-SpeakerAngle[i]) /
|
||||
(F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
|
||||
gains[Speaker2Chan[i]] = aluSqrt(1.0f-a) * ingain;
|
||||
gains[Speaker2Chan[0]] = aluSqrt( a) * ingain;
|
||||
return;
|
||||
}
|
||||
|
||||
langle = angle - hwidth;
|
||||
rangle = angle + hwidth;
|
||||
if(langle < -F_PI)
|
||||
langle += F_PI*2.0f;
|
||||
if(rangle > F_PI)
|
||||
rangle -= F_PI*2.0f;
|
||||
|
||||
if(langle > rangle)
|
||||
{
|
||||
/* langle and rangle are swapped to keep the langle<rangle assumption
|
||||
* true, which keeps the following calculations sane. This inverts the
|
||||
* results, so speakers within the original field end up as 0 and
|
||||
* outside end up as 1. A fixup is done afterward to make sure the
|
||||
* results are as expected. */
|
||||
ALfloat tmp = rangle;
|
||||
rangle = langle;
|
||||
langle = tmp;
|
||||
inverted = AL_TRUE;
|
||||
}
|
||||
|
||||
/* First speaker */
|
||||
i = 0;
|
||||
{
|
||||
ALuint last = device->NumChan-1;
|
||||
|
||||
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f;
|
||||
else if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
|
||||
{
|
||||
a = (langle-SpeakerAngle[i]) /
|
||||
(SpeakerAngle[i+1]-SpeakerAngle[i]);
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f - a;
|
||||
}
|
||||
else if(SpeakerAngle[i] > rangle)
|
||||
{
|
||||
a = (F_PI*2.0f + rangle-SpeakerAngle[last]) /
|
||||
(F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
|
||||
tmpgains[Speaker2Chan[i]] = a;
|
||||
}
|
||||
else if(rangle > SpeakerAngle[last])
|
||||
{
|
||||
a = (rangle-SpeakerAngle[last]) /
|
||||
(F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
|
||||
tmpgains[Speaker2Chan[i]] = a;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 1;i < device->NumChan-1;i++)
|
||||
{
|
||||
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f;
|
||||
else if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
|
||||
{
|
||||
a = (langle-SpeakerAngle[i]) /
|
||||
(SpeakerAngle[i+1]-SpeakerAngle[i]);
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f - a;
|
||||
}
|
||||
else if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
|
||||
{
|
||||
a = (rangle-SpeakerAngle[i-1]) /
|
||||
(SpeakerAngle[i]-SpeakerAngle[i-1]);
|
||||
tmpgains[Speaker2Chan[i]] = a;
|
||||
}
|
||||
}
|
||||
|
||||
/* Last speaker */
|
||||
i = device->NumChan-1;
|
||||
{
|
||||
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f;
|
||||
else if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
|
||||
{
|
||||
a = (rangle-SpeakerAngle[i-1]) /
|
||||
(SpeakerAngle[i]-SpeakerAngle[i-1]);
|
||||
tmpgains[Speaker2Chan[i]] = a;
|
||||
}
|
||||
else if(SpeakerAngle[i] < langle)
|
||||
{
|
||||
ALfloat nextangle = SpeakerAngle[0] + F_PI*2.0f;
|
||||
a = (langle-SpeakerAngle[i]) /
|
||||
(nextangle-SpeakerAngle[i]);
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f - a;
|
||||
}
|
||||
else if(SpeakerAngle[0] > langle)
|
||||
{
|
||||
a = (langle-SpeakerAngle[i] - F_PI*2.0f) /
|
||||
(SpeakerAngle[0]-SpeakerAngle[i] - F_PI*2.0f);
|
||||
tmpgains[Speaker2Chan[i]] = 1.0f - a;
|
||||
}
|
||||
}
|
||||
|
||||
if(inverted)
|
||||
{
|
||||
for(i = 0;i < device->NumChan;i++)
|
||||
{
|
||||
enum Channel chan = device->Speaker2Chan[i];
|
||||
gains[chan] = aluSqrt(1.0f - tmpgains[chan]) * ingain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i = 0;i < device->NumChan;i++)
|
||||
{
|
||||
enum Channel chan = device->Speaker2Chan[i];
|
||||
gains[chan] = aluSqrt(tmpgains[chan]) * ingain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALvoid aluInitPanning(ALCdevice *Device)
|
||||
{
|
||||
const char *layoutname = NULL;
|
||||
|
||||
@@ -298,6 +298,8 @@ static __inline void aluNormalize(ALfloat *inVector)
|
||||
ALvoid aluInitPanning(ALCdevice *Device);
|
||||
ALint aluCart2LUTpos(ALfloat im, ALfloat re);
|
||||
|
||||
ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat *gains);
|
||||
|
||||
ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
|
||||
ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user