Title: [106580] trunk
Revision
106580
Author
[email protected]
Date
2012-02-02 12:46:43 -0800 (Thu, 02 Feb 2012)

Log Message

Constant values to set "distanceModel" are undefined
https://bugs.webkit.org/show_bug.cgi?id=74273

Patch by Raymond Toy <[email protected]> on 2012-02-02
Reviewed by Kenneth Russell.

Source/WebCore:

Tests: webaudio/distance-exponential.html
       webaudio/distance-inverse.html
       webaudio/distance-linear.html

* webaudio/AudioPannerNode.h: Define enum for the new constants
for the distance models.
* webaudio/AudioPannerNode.idl: Define matching constants for the
distance models.

LayoutTests:

* webaudio/distance-exponential-expected.txt: Added.
* webaudio/distance-exponential.html: Added.
* webaudio/distance-inverse-expected.txt: Added.
* webaudio/distance-inverse.html: Added.
* webaudio/distance-linear-expected.txt: Added.
* webaudio/distance-linear.html: Added.
* webaudio/resources/distance-model-testing.js: Added.
(createImpulseBuffer):
(linearDistance):
(exponentialDistance):
(inverseDistance):
(createGraph):
(startSources):
(equalPowerGain):
(checkDistanceResult.return.renderedBuffer):
(checkDistanceResult):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (106579 => 106580)


--- trunk/LayoutTests/ChangeLog	2012-02-02 20:29:20 UTC (rev 106579)
+++ trunk/LayoutTests/ChangeLog	2012-02-02 20:46:43 UTC (rev 106580)
@@ -1,5 +1,29 @@
 2012-02-02  Raymond Toy  <[email protected]>
 
+        Constant values to set "distanceModel" are undefined
+        https://bugs.webkit.org/show_bug.cgi?id=74273
+
+        Reviewed by Kenneth Russell.
+
+        * webaudio/distance-exponential-expected.txt: Added.
+        * webaudio/distance-exponential.html: Added.
+        * webaudio/distance-inverse-expected.txt: Added.
+        * webaudio/distance-inverse.html: Added.
+        * webaudio/distance-linear-expected.txt: Added.
+        * webaudio/distance-linear.html: Added.
+        * webaudio/resources/distance-model-testing.js: Added.
+        (createImpulseBuffer):
+        (linearDistance):
+        (exponentialDistance):
+        (inverseDistance):
+        (createGraph):
+        (startSources):
+        (equalPowerGain):
+        (checkDistanceResult.return.renderedBuffer):
+        (checkDistanceResult):
+
+2012-02-02  Raymond Toy  <[email protected]>
+
         Illegal panner model values should throw an exception
         https://bugs.webkit.org/show_bug.cgi?id=77235
 

Added: trunk/LayoutTests/webaudio/distance-exponential-expected.txt (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-exponential-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-exponential-expected.txt	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,12 @@
+Test exponential distance model of AudioPannerNode.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Distance model value matched expected value.
+PASS Number of impulses found matches number of panner nodes.
+PASS Distance gains are correct.
+PASS Distance test passed for distance model 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webaudio/distance-exponential.html (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-exponential.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-exponential.html	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <link rel="stylesheet" href=""
+    <script src=""
+    <script src=""
+    <script src=""
+  </head>
+
+  <body>
+    <div id="description"></div>
+    <div id="console"></div>
+
+    <script>
+      description("Test exponential distance model of AudioPannerNode.");
+
+      function runTest() {
+          if (window.layoutTestController) {
+              layoutTestController.dumpAsText();
+              layoutTestController.waitUntilDone();
+          }
+
+          window.jsTestIsAsync = true;
+
+          // Create offline audio context.
+          context = new webkitAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
+
+          // Temp panner node so we can get the EXPONENTIAL_DISTANCE value.
+          var tempPanner = context.createPanner();
+          createTestAndRun(context, tempPanner.EXPONENTIAL_DISTANCE, 2);
+      }
+
+      runTest();
+      successfullyParsed = true;
+
+    </script>
+
+<script src=""
+  </body>
+</html>

Added: trunk/LayoutTests/webaudio/distance-inverse-expected.txt (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-inverse-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-inverse-expected.txt	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,12 @@
+Test inverse distance model of AudioPannerNode.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Distance model value matched expected value.
+PASS Number of impulses found matches number of panner nodes.
+PASS Distance gains are correct.
+PASS Distance test passed for distance model 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webaudio/distance-inverse.html (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-inverse.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-inverse.html	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <link rel="stylesheet" href=""
+    <script src=""
+    <script src=""
+    <script src=""
+  </head>
+
+  <body>
+    <div id="description"></div>
+    <div id="console"></div>
+
+    <script>
+      description("Test inverse distance model of AudioPannerNode.");
+
+      function runTest() {
+          if (window.layoutTestController) {
+              layoutTestController.dumpAsText();
+              layoutTestController.waitUntilDone();
+          }
+
+          window.jsTestIsAsync = true;
+
+          // Create offline audio context.
+          context = new webkitAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
+
+          // Temp panner node so we can get the INVERSE_DISTANCE value.
+          var tempPanner = context.createPanner();
+          createTestAndRun(context, tempPanner.INVERSE_DISTANCE, 1);
+      }
+
+      runTest();
+      successfullyParsed = true;
+
+    </script>
+
+<script src=""
+  </body>
+</html>

Added: trunk/LayoutTests/webaudio/distance-linear-expected.txt (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-linear-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-linear-expected.txt	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,12 @@
+Test linear distance model of AudioPannerNode.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Distance model value matched expected value.
+PASS Number of impulses found matches number of panner nodes.
+PASS Distance gains are correct.
+PASS Distance test passed for distance model 0
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/webaudio/distance-linear.html (0 => 106580)


--- trunk/LayoutTests/webaudio/distance-linear.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/distance-linear.html	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <link rel="stylesheet" href=""
+    <script src=""
+    <script src=""
+    <script src=""
+  </head>
+
+  <body>
+    <div id="description"></div>
+    <div id="console"></div>
+
+    <script>
+      description("Test linear distance model of AudioPannerNode.");
+
+      function runTest() {
+          if (window.layoutTestController) {
+              layoutTestController.dumpAsText();
+              layoutTestController.waitUntilDone();
+          }
+
+          window.jsTestIsAsync = true;
+
+          // Create offline audio context.
+          context = new webkitAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
+
+          // Create temp panner to get LINEAR_DISTANCE value for testing.
+          var pannerModel = context.createPanner();
+          createTestAndRun(context, pannerModel.LINEAR_DISTANCE, 0);
+      }
+
+      runTest();
+      successfullyParsed = true;
+
+    </script>
+
+<script src=""
+  </body>
+</html>

Added: trunk/LayoutTests/webaudio/resources/distance-model-testing.js (0 => 106580)


--- trunk/LayoutTests/webaudio/resources/distance-model-testing.js	                        (rev 0)
+++ trunk/LayoutTests/webaudio/resources/distance-model-testing.js	2012-02-02 20:46:43 UTC (rev 106580)
@@ -0,0 +1,212 @@
+var sampleRate = 44100.0;
+
+// How many panner nodes to create for the test.
+var nodesToCreate = 100;
+
+// Time step when each panner node starts.
+var timeStep = 0.001;
+
+// Make sure we render long enough to get all of our nodes.
+var renderLengthSeconds = timeStep * (nodesToCreate + 1);
+
+// Length of an impulse signal.
+var pulseLengthFrames = Math.round(timeStep * sampleRate);
+
+// Globals to make debugging a little easier.
+var context;
+var impulse;
+var bufferSource;
+var panner;
+var position;
+var time;
+      
+// For the record, these distance formulas were taken from the OpenAL
+// spec
+// (http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf),
+// not the code.  The Web Audio spec follows the OpenAL formulas.
+
+function linearDistance(panner, x, y, z) {
+    var distance = Math.sqrt(x * x + y * y + z * z);
+    distance = Math.min(distance, panner.maxDistance);
+    var rolloff = panner.rolloffFactor;
+    var gain = (1 - rolloff * (distance - panner.refDistance) / (panner.maxDistance - panner.refDistance));
+
+    return gain;
+}
+
+function inverseDistance(panner, x, y, z) {
+    var distance = Math.sqrt(x * x + y * y + z * z);
+    distance = Math.min(distance, panner.maxDistance);
+    var rolloff = panner.rolloffFactor;
+    var gain = panner.refDistance / (panner.refDistance + rolloff * (distance - panner.refDistance));
+
+    return gain;
+}
+
+function exponentialDistance(panner, x, y, z) {
+    var distance = Math.sqrt(x * x + y * y + z * z);
+    distance = Math.min(distance, panner.maxDistance);
+    var rolloff = panner.rolloffFactor;
+    var gain = Math.pow(distance / panner.refDistance, -rolloff);
+
+    return gain;
+}
+
+// This array must be arranged in the numeric order of the distance
+// model values.
+var distanceModelFunction = [linearDistance, inverseDistance, exponentialDistance];
+
+function createGraph(context, distanceModel, nodeCount) {
+    bufferSource = new Array(nodeCount);
+    panner = new Array(nodeCount);
+    position = new Array(nodeCount);
+    time = new Array(nodesToCreate);
+
+    impulse = createImpulseBuffer(context, pulseLengthFrames);
+
+    // Create all the sources and panners.
+    //
+    // We MUST use the EQUALPOWER panning model so that we can easily
+    // figure out the gain introduced by the panner.
+    //
+    // We want to stay in the middle of the panning range, which means
+    // we want to stay on the z-axis.  If we don't, then the effect of
+    // panning model will be much more complicated.  We're not testing
+    // the panner, but the distance model, so we want the panner effect
+    // to be simple.
+    //
+    // The panners are placed at a uniform intervals between the panner
+    // reference distance and the panner max distance.  The source is
+    // also started at regular intervals.
+    for (var k = 0; k < nodeCount; ++k) {
+        bufferSource[k] = context.createBufferSource();
+        bufferSource[k].buffer = impulse;
+
+        panner[k] = context.createPanner();
+        panner[k].panningModel = panner.EQUALPOWER;
+        panner[k].distanceModel = distanceModel;
+
+        var distanceStep = (panner[k].maxDistance - panner[k].refDistance) / nodeCount;
+        position[k] = distanceStep * k + panner[k].refDistance;
+        panner[k].setPosition(0, 0, position[k]);
+
+        bufferSource[k].connect(panner[k]);
+        panner[k].connect(context.destination);
+
+        time[k] = k * timeStep;
+        bufferSource[k].noteOn(time[k]);
+    }
+}
+
+// distanceModel should be the distance model constant like
+// LINEAR_DISTANCE, INVERSE_DISTANCE, and EXPONENTIAL_DISTANCE.  The
+// expectedModel is the expected actual numeric value of the constant.
+function createTestAndRun(context, distanceModel, expectedModel) {
+    // To test the distance models, we create a number of panners at
+    // uniformly spaced intervals on the z-axis.  Each of these are
+    // started at equally spaced time intervals.  After rendering the
+    // signals, we examine where each impulse is located and the
+    // attenuation of the impulse.  The attenuation is compared
+    // against our expected attenuation.
+
+    createGraph(context, distanceModel, nodesToCreate);
+
+    context._oncomplete_ = checkDistanceResult(distanceModel, expectedModel);
+    context.startRendering();
+}
+
+// The gain caused by the EQUALPOWER panning model, if we stay on the
+// z axis, with the default orientations.
+function equalPowerGain() {
+    return Math.SQRT1_2;
+}
+
+function checkDistanceResult(model, expectedModel) {
+    return function(event) {
+        renderedBuffer = event.renderedBuffer;
+        renderedData = renderedBuffer.getChannelData(0);
+
+        // The max allowed error between the actual gain and the expected
+        // value.  This is determined experimentally.  Set to 0 to see what
+        // the actual errors are.
+        var maxAllowedError = 2.3e-6;
+   
+        var success = true;
+
+        // Number of impulses we found in the rendered result.
+        var impulseCount = 0;
+
+        // Maximum relative error in the gain of the impulses.
+        var maxError = 0;
+
+        // Array of locations of the impulses that were not at the
+        // expected location.  (Contains the actual and expected frame
+        // of the impulse.)
+        var impulsePositionErrors = new Array();
+
+        // Step through the rendered data to find all the non-zero points
+        // so we can find where our distance-attenuated impulses are.
+        // These are tested against the expected attenuations at that
+        // distance.
+        for (var k = 0; k < renderedData.length; ++k) {
+            if (renderedData[k] != 0) {
+                var distanceFunction = distanceModelFunction[panner[impulseCount].distanceModel];
+                var expected = distanceFunction(panner[impulseCount], 0, 0, position[impulseCount]);
+
+                // Adjust for the center-panning of the EQUALPOWER panning
+                // model that we're using.
+                expected *= equalPowerGain();
+
+                var error = Math.abs(renderedData[k] - expected) / Math.abs(expected);
+
+                maxError = Math.max(maxError, Math.abs(error));
+
+                // Keep track of any impulses that aren't where we expect them
+                // to be.
+                var expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
+                if (k != expectedOffset) {
+                    impulsePositionErrors.push({ actual : k, expected : expectedOffset});
+                }
+                ++impulseCount;
+            }
+        }
+
+        if (model == expectedModel) {
+            testPassed("Distance model value matched expected value.");
+        } else {
+            testFailed("Distance model value does not match expected value.");
+            success = false;
+        }    
+
+        if (impulseCount == nodesToCreate) {
+            testPassed("Number of impulses found matches number of panner nodes.");
+        } else {
+            testFailed("Number of impulses is incorrect.  Found " + impulseCount + " but expected " + nodesToCreate + ".");
+            success = false;
+        }
+
+        if (maxError <= maxAllowedError) {
+            testPassed("Distance gains are correct.");
+        } else {
+            testFailed("Distance gains are incorrect.  Max rel error = " + maxError + " (maxAllowedError = " + maxAllowedError + ")");
+            success = false;
+        }
+
+        // Display any timing errors that we found.
+        if (impulsePositionErrors.length > 0) {
+            success = false;
+            testFailed(impulsePositionErrors.length + " timing errors found");
+            for (var k = 0; k < impulsePositionErrors.length; ++k) {
+                testFailed("Sample at frame " + impulsePositionErrors[k].actual + " but expected " + impulsePositionErrors[k].expected);
+            }
+        }
+
+        if (success) {
+            testPassed("Distance test passed for distance model " + model);
+        } else {
+            testFailed("Distance test failed for distance model " + model);
+        }
+
+        finishJSTest();
+    }
+}

Modified: trunk/Source/WebCore/ChangeLog (106579 => 106580)


--- trunk/Source/WebCore/ChangeLog	2012-02-02 20:29:20 UTC (rev 106579)
+++ trunk/Source/WebCore/ChangeLog	2012-02-02 20:46:43 UTC (rev 106580)
@@ -1,5 +1,21 @@
 2012-02-02  Raymond Toy  <[email protected]>
 
+        Constant values to set "distanceModel" are undefined
+        https://bugs.webkit.org/show_bug.cgi?id=74273
+
+        Reviewed by Kenneth Russell.
+
+        Tests: webaudio/distance-exponential.html
+               webaudio/distance-inverse.html
+               webaudio/distance-linear.html
+
+        * webaudio/AudioPannerNode.h: Define enum for the new constants
+        for the distance models.
+        * webaudio/AudioPannerNode.idl: Define matching constants for the
+        distance models.
+
+2012-02-02  Raymond Toy  <[email protected]>
+
         Illegal panner model values should throw an exception
         https://bugs.webkit.org/show_bug.cgi?id=77235
 

Modified: trunk/Source/WebCore/webaudio/AudioPannerNode.h (106579 => 106580)


--- trunk/Source/WebCore/webaudio/AudioPannerNode.h	2012-02-02 20:29:20 UTC (rev 106579)
+++ trunk/Source/WebCore/webaudio/AudioPannerNode.h	2012-02-02 20:46:43 UTC (rev 106580)
@@ -53,6 +53,14 @@
         SOUNDFIELD = 2,
     };
 
+    // These must be defined as in the .idl file and must match those
+    // in the DistanceEffect class.
+    enum {
+        LINEAR_DISTANCE = 0,
+        INVERSE_DISTANCE = 1,
+        EXPONENTIAL_DISTANCE = 2,
+    };
+    
     static PassRefPtr<AudioPannerNode> create(AudioContext* context, float sampleRate)
     {
         return adoptRef(new AudioPannerNode(context, sampleRate));

Modified: trunk/Source/WebCore/webaudio/AudioPannerNode.idl (106579 => 106580)


--- trunk/Source/WebCore/webaudio/AudioPannerNode.idl	2012-02-02 20:29:20 UTC (rev 106579)
+++ trunk/Source/WebCore/webaudio/AudioPannerNode.idl	2012-02-02 20:46:43 UTC (rev 106580)
@@ -32,6 +32,11 @@
         const unsigned short HRTF = 1;
         const unsigned short SOUNDFIELD = 2;
 
+        // Distance model
+        const unsigned short LINEAR_DISTANCE = 0;
+        const unsigned short INVERSE_DISTANCE = 1;
+        const unsigned short EXPONENTIAL_DISTANCE = 2;
+
         // Default model for stereo is HRTF 
         // FIXME: use unsigned short when glue generation supports it
         attribute unsigned long panningModel
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to