aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2012-04-28 12:12:02 -0700
committerChris Robinson <[email protected]>2012-04-28 12:12:02 -0700
commit74e128bd0fda9ae1208e340db3f735bc98551c3f (patch)
tree85609a12eb250021cd49012bde51ea343e24a099 /Alc
parentc34d78f41718f859709700b06bdfdf6640890275 (diff)
Fix ComputeAngleGains
The old code would improperly handle speakers just inside or outside the coverage area if it had to be inverted. It also didn't properly handle when only one speaker was outside of the covered area.
Diffstat (limited to 'Alc')
-rw-r--r--Alc/panning.c160
1 files changed, 99 insertions, 61 deletions
diff --git a/Alc/panning.c b/Alc/panning.c
index 0433fd3d..8a53047a 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -172,14 +172,18 @@ ALint aluCart2LUTpos(ALfloat im, ALfloat re)
*/
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;
+ enum Channel Speaker2Chan[MAXCHANNELS];
+ ALfloat SpeakerAngle[MAXCHANNELS];
ALfloat langle, rangle;
ALfloat a;
ALuint i;
+ for(i = 0;i < device->NumChan;i++)
+ Speaker2Chan[i] = device->Speaker2Chan[i];
+ for(i = 0;i < device->NumChan;i++)
+ SpeakerAngle[i] = device->SpeakerAngle[i];
+
/* Some easy special-cases first... */
if(device->NumChan == 1 || hwidth >= F_PI)
{
@@ -198,7 +202,7 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
{
if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
{
- /* Sound is between speaker i and i+1 */
+ /* Sound is between speakers i and i+1 */
a = (angle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
gains[Speaker2Chan[i]] = aluSqrt(1.0f-a) * ingain;
@@ -216,112 +220,146 @@ ALvoid ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth,
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)
+ if(aluFabs(angle)+hwidth <= F_PI)
+ {
+ /* Good, the coverage area ins fully inside -pi...+pi. */
+ langle = angle-hwidth;
+ rangle = angle+hwidth;
+ }
+ else
{
- /* 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;
+ /* The coverage area would go outside of -pi...+pi. Instead, rotate the
+ * speaker angles so it was be as if angle=0, and keep them wrapped
+ * within -pi...+pi. */
+ langle = -hwidth;
+ rangle = +hwidth;
+
+ for(i = 0;i < device->NumChan;i++)
+ {
+ SpeakerAngle[i] -= angle;
+ if(SpeakerAngle[i] > F_PI)
+ SpeakerAngle[i] -= F_PI*2.0f;
+ else if(SpeakerAngle[i] < -F_PI)
+ SpeakerAngle[i] += F_PI*2.0f;
+ }
+
+ /* The speaker angles are expected to be in ascending order. There
+ * should be a better way to resort the lists... */
+ for(i = 0;i < device->NumChan-1;i++)
+ {
+ ALuint min = i;
+ ALuint j;
+
+ for(j = i+1;j < device->NumChan;j++)
+ {
+ if(SpeakerAngle[j] < SpeakerAngle[min])
+ min = j;
+ }
+
+ if(min != i)
+ {
+ ALfloat tmpf;
+ enum Channel tmpc;
+
+ tmpf = SpeakerAngle[i];
+ SpeakerAngle[i] = SpeakerAngle[min];
+ SpeakerAngle[min] = tmpf;
+
+ tmpc = Speaker2Chan[i];
+ Speaker2Chan[i] = Speaker2Chan[min];
+ Speaker2Chan[min] = tmpc;
+ }
+ }
}
/* First speaker */
i = 0;
- {
+ do {
ALuint last = device->NumChan-1;
+ enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
- tmpgains[Speaker2Chan[i]] = 1.0f;
- else if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
+ {
+ tmpgains[chan] = 1.0f;
+ continue;
+ }
+
+ if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
{
a = (langle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
- tmpgains[Speaker2Chan[i]] = 1.0f - a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
- else if(SpeakerAngle[i] > rangle)
+ if(SpeakerAngle[i] > rangle)
{
a = (F_PI*2.0f + rangle-SpeakerAngle[last]) /
(F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
- tmpgains[Speaker2Chan[i]] = a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
- else if(rangle > SpeakerAngle[last])
+ else if(SpeakerAngle[last] < rangle)
{
a = (rangle-SpeakerAngle[last]) /
(F_PI*2.0f + SpeakerAngle[i]-SpeakerAngle[last]);
- tmpgains[Speaker2Chan[i]] = a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
- }
+ } while(0);
for(i = 1;i < device->NumChan-1;i++)
{
+ enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
- tmpgains[Speaker2Chan[i]] = 1.0f;
- else if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
+ {
+ tmpgains[chan] = 1.0f;
+ continue;
+ }
+
+ if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
{
a = (langle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
- tmpgains[Speaker2Chan[i]] = 1.0f - a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
- else if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+ if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
{
a = (rangle-SpeakerAngle[i-1]) /
(SpeakerAngle[i]-SpeakerAngle[i-1]);
- tmpgains[Speaker2Chan[i]] = a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
}
/* Last speaker */
i = device->NumChan-1;
- {
+ do {
+ enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
+ {
tmpgains[Speaker2Chan[i]] = 1.0f;
- else if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+ continue;
+ }
+ if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
{
a = (rangle-SpeakerAngle[i-1]) /
(SpeakerAngle[i]-SpeakerAngle[i-1]);
- tmpgains[Speaker2Chan[i]] = a;
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
- else if(SpeakerAngle[i] < langle)
+ 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;
+ a = (langle-SpeakerAngle[i]) /
+ (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 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;
+ a = (F_PI*2.0f + langle-SpeakerAngle[i]) /
+ (F_PI*2.0f + SpeakerAngle[0]-SpeakerAngle[i]);
+ tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
- }
+ } while(0);
- if(inverted)
+ for(i = 0;i < device->NumChan;i++)
{
- 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;
- }
+ enum Channel chan = device->Speaker2Chan[i];
+ gains[chan] = aluSqrt(tmpgains[chan]) * ingain;
}
}