diff options
author | Chris Robinson <[email protected]> | 2012-04-28 12:12:02 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2012-04-28 12:12:02 -0700 |
commit | 74e128bd0fda9ae1208e340db3f735bc98551c3f (patch) | |
tree | 85609a12eb250021cd49012bde51ea343e24a099 | |
parent | c34d78f41718f859709700b06bdfdf6640890275 (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.
-rw-r--r-- | Alc/panning.c | 160 |
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; } } |