Bug 957024 - Update PannerNode distance calculations to match the web audio spec; r=karlt

Distances less than refDistance should be treated as refDistance when calculating
the gain.

MozReview-Commit-ID: JASGb7jLp5L

--HG--
extra : rebase_source : 24e0207b7e6482000ec134bbde59ce448eee25f7
This commit is contained in:
Dan Minor 2016-08-16 11:07:12 -04:00
Родитель 8f8236ba1e
Коммит 397fdefcf6
3 изменённых файлов: 99 добавлений и 12 удалений

Просмотреть файл

@ -234,14 +234,14 @@ public:
void ComputeAzimuthAndElevation(const ThreeDPoint& position, float& aAzimuth, float& aElevation);
float ComputeConeGain(const ThreeDPoint& position, const ThreeDPoint& orientation);
// Compute how much the distance contributes to the gain reduction.
float ComputeDistanceGain(const ThreeDPoint& position);
double ComputeDistanceGain(const ThreeDPoint& position);
void EqualPowerPanningFunction(const AudioBlock& aInput, AudioBlock* aOutput, StreamTime tick);
void HRTFPanningFunction(const AudioBlock& aInput, AudioBlock* aOutput, StreamTime tick);
float LinearGainFunction(float aDistance);
float InverseGainFunction(float aDistance);
float ExponentialGainFunction(float aDistance);
float LinearGainFunction(double aDistance);
float InverseGainFunction(double aDistance);
float ExponentialGainFunction(double aDistance);
ThreeDPoint ConvertAudioParamTimelineTo3DP(AudioParamTimeline& aX, AudioParamTimeline& aY, AudioParamTimeline& aZ, StreamTime& tick);
@ -267,7 +267,7 @@ public:
nsAutoPtr<HRTFPanner> mHRTFPanner;
typedef void (PannerNodeEngine::*PanningModelFunction)(const AudioBlock& aInput, AudioBlock* aOutput, StreamTime tick);
PanningModelFunction mPanningModelFunction;
typedef float (PannerNodeEngine::*DistanceModelFunction)(float aDistance);
typedef float (PannerNodeEngine::*DistanceModelFunction)(double aDistance);
DistanceModelFunction mDistanceModelFunction;
AudioParamTimeline mPositionX;
AudioParamTimeline mPositionY;
@ -370,21 +370,21 @@ void PannerNode::DestroyMediaStream()
// Those three functions are described in the spec.
float
PannerNodeEngine::LinearGainFunction(float aDistance)
PannerNodeEngine::LinearGainFunction(double aDistance)
{
return 1 - mRolloffFactor * (aDistance - mRefDistance) / (mMaxDistance - mRefDistance);
return 1 - mRolloffFactor * (std::max(std::min(aDistance, mMaxDistance), mRefDistance) - mRefDistance) / (mMaxDistance - mRefDistance);
}
float
PannerNodeEngine::InverseGainFunction(float aDistance)
PannerNodeEngine::InverseGainFunction(double aDistance)
{
return mRefDistance / (mRefDistance + mRolloffFactor * (aDistance - mRefDistance));
return mRefDistance / (mRefDistance + mRolloffFactor * (std::max(aDistance, mRefDistance) - mRefDistance));
}
float
PannerNodeEngine::ExponentialGainFunction(float aDistance)
PannerNodeEngine::ExponentialGainFunction(double aDistance)
{
return pow(aDistance / mRefDistance, -mRolloffFactor);
return pow(std::max(aDistance, mRefDistance) / mRefDistance, -mRolloffFactor);
}
void
@ -683,7 +683,7 @@ PannerNodeEngine::ComputeConeGain(const ThreeDPoint& position,
return gain;
}
float
double
PannerNodeEngine::ComputeDistanceGain(const ThreeDPoint& position)
{
ThreeDPoint distanceVec = position - mListenerPosition;

Просмотреть файл

@ -173,6 +173,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') || (os == 'mac
[test_pannerNode.html]
[test_pannerNode_equalPower.html]
[test_pannerNodeAbove.html]
[test_pannerNodeAtZeroDistance.html]
[test_pannerNodeChannelCount.html]
[test_pannerNodeHRTFSymmetry.html]
[test_pannerNodeTail.html]

Просмотреть файл

@ -0,0 +1,86 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test PannerNode produces output even when the even when the distance is from the listener is zero</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="webaudio.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
var BUF_SIZE = 128;
var types = [
"equalpower",
"HRTF"
]
var finished = types.length;
function finish() {
if (!--finished) {
SimpleTest.finish();
}
}
function test(type) {
var ac = new OfflineAudioContext(1, BUF_SIZE, 44100);
// A sine to be used to fill the buffers
function sine(t) {
return Math.sin(440 * 2 * Math.PI * t / ac.sampleRate);
}
var monoBuffer = ac.createBuffer(1, BUF_SIZE, ac.sampleRate);
for (var i = 0; i < BUF_SIZE; ++i) {
monoBuffer.getChannelData(0)[i] = sine(i);
}
var monoSource = ac.createBufferSource();
monoSource.buffer = monoBuffer;
monoSource.start(0);
var panner = ac.createPanner();
panner.distanceModel = "linear";
panner.refDistance = 1;
panner.positionX.value = 0;
panner.positionY.value = 0;
panner.positionZ.value = 0;
monoSource.connect(panner);
var panner2 = ac.createPanner();
panner2.distanceModel = "inverse";
panner2.refDistance = 1;
panner2.positionX.value = 0;
panner2.positionY.value = 0;
panner2.positionZ.value = 0;
panner.connect(panner2);
var panner3 = ac.createPanner();
panner3.distanceModel = "exponential";
panner3.refDistance = 1;
panner3.positionX.value = 0;
panner3.positionY.value = 0;
panner3.positionZ.value = 0;
panner2.connect(panner3);
panner3.connect(ac.destination);
ac.startRendering().then(function(buffer) {
compareBuffers(buffer, monoBuffer);
finish();
});
}
addLoadEvent(function() {
types.forEach(test);
});
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>