WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-75767-20120111130655.patch (text/plain), 15.08 KB, created by
Raymond Toy
on 2012-01-11 13:06:56 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Raymond Toy
Created:
2012-01-11 13:06:56 PST
Size:
15.08 KB
patch
obsolete
>Subversion Revision: 104657 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 1d6e3f47d63ea724649dcb19639620f34d1770fd..cb560c7111d87542699378c7334deab7490017a3 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,15 @@ >+2012-01-09 Raymond Toy <rtoy@google.com> >+ >+ EQUALPOWER panner incorrectly computes gain >+ https://bugs.webkit.org/show_bug.cgi?id=75767 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Layout test added. >+ >+ * platform/audio/EqualPowerPanner.cpp: >+ (WebCore::EqualPowerPanner::pan): Correct the formula. >+ > 2012-01-10 Daniel Cheng <dcheng@chromium.org> > > [chromium] Pasteboard::documentFragment should fall back to text if there's no HTML text >diff --git a/Source/WebCore/platform/audio/EqualPowerPanner.cpp b/Source/WebCore/platform/audio/EqualPowerPanner.cpp >index 13a19d6cd4451d7b2f9882b50c4ed9e00320b3b6..0da762236409172a58456ff0b6dd72fe58bc7849 100644 >--- a/Source/WebCore/platform/audio/EqualPowerPanner.cpp >+++ b/Source/WebCore/platform/audio/EqualPowerPanner.cpp >@@ -84,8 +84,8 @@ void EqualPowerPanner::pan(double azimuth, double /*elevation*/, AudioBus* input > // Pan smoothly from left to right with azimuth going from -90 -> +90 degrees. > double desiredPanPosition = (azimuth + 90) / 180; > >- double desiredGainL = 0.5 * cos(piDouble * desiredPanPosition) + 0.5; >- double desiredGainR = sqrt(1.0 - desiredGainL*desiredGainL); >+ double desiredGainL = cos(0.5 * piDouble * desiredPanPosition); >+ double desiredGainR = sin(0.5 * piDouble * desiredPanPosition); > > // Don't de-zipper on first render call. > if (m_isFirstRender) { >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index e19c48e8d6d0b02ee7ba61183071c614a44605d2..c1c9aeaf4f6b2b8103a587fabffb8868de2e2f12 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,14 @@ >+2012-01-11 Raymond Toy <rtoy@chromium.org> >+ EQUALPOWER panner incorrectly computes gain >+ https://bugs.webkit.org/show_bug.cgi?id=75767 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webaudio/panner-equalpower.html: >+ * webaudio/panner-equalpower-expected.txt: >+ * webaudio/resources/panner-model-testing.js: >+ Test for EQUALPOWER panner. >+ > 2012-01-10 Sheriff Bot <webkit.review.bot@gmail.com> > > Unreviewed, rolling out r104543. >diff --git a/LayoutTests/webaudio/panner-equalpower-expected.txt b/LayoutTests/webaudio/panner-equalpower-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..a9b90aa020ef4589b50f9c75c914a988e033f418 >--- /dev/null >+++ b/LayoutTests/webaudio/panner-equalpower-expected.txt >@@ -0,0 +1,12 @@ >+Test equal-power panner model of AudioPannerNode. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+PASS Number of nodes is correct. >+PASS Left channel panner values are correct. >+PASS Right channel panner values are correct. >+PASS EqualPower panner test passed for panner model 0 >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/webaudio/panner-equalpower.html b/LayoutTests/webaudio/panner-equalpower.html >new file mode 100644 >index 0000000000000000000000000000000000000000..5a03d80e09a17dddcb30e8b342c39a5d102014b5 >--- /dev/null >+++ b/LayoutTests/webaudio/panner-equalpower.html >@@ -0,0 +1,45 @@ >+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> >+<html> >+ <head> >+ <link rel="stylesheet" href="../fast/js/resources/js-test-style.css"/> >+ <script src="resources/audio-testing.js"></script> >+ <script src="../fast/js/resources/js-test-pre.js"></script> >+ <script src="resources/panner-model-testing.js"></script> >+ </head> >+ >+ <body> >+ <div id="description"></div> >+ <div id="console"></div> >+ >+ <script> >+ description("Test equal-power panner 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); >+ >+ // Threshold experimentally determined. >+ var threshold = .00019; >+ >+ // Temp panner node so we can get the distance model and >+ // panning model values.. >+ var tempPanner = context.createPanner(); >+ >+ createTestAndRun(context, tempPanner.LINEAR_DISTANCE, tempPanner.EQUALPOWER, nodesToCreate, threshold); >+ } >+ >+ runTest(); >+ successfullyParsed = true; >+ >+ </script> >+ >+<script src="../fast/js/resources/js-test-post.js"></script> >+ </body> >+</html> >diff --git a/LayoutTests/webaudio/resources/panner-model-testing.js b/LayoutTests/webaudio/resources/panner-model-testing.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d40f20e63506c610133de2c1d12c6e57ba28de95 >--- /dev/null >+++ b/LayoutTests/webaudio/resources/panner-model-testing.js >@@ -0,0 +1,297 @@ >+var sampleRate = 44100.0; >+ >+var renderLengthSeconds = 8; >+var pulseLengthSeconds = 1; >+var pulseLengthFrames = pulseLengthSeconds * sampleRate; >+ >+// How many panner nodes to create for the test >+var nodesToCreate = 100; >+ >+// Time step when each panner node starts. >+var timeStep = 0.05; >+ >+// These are global mostly for debugging. >+var context; >+var impulse; >+var bufferSource; >+var panner; >+var position; >+var time; >+ >+var renderedBuffer; >+var renderedLeft; >+var renderedRight; >+ >+function createImpulseBuffer(context, sampleFrameLength) { >+ var audioBuffer = context.createBuffer(1, 1000, context.sampleRate); >+ var n = audioBuffer.length; >+ var dataL = audioBuffer.getChannelData(0); >+ >+ for (var k = 0; k < n; ++k) { >+ dataL[k] = 0; >+ } >+ dataL[0] = 1; >+ >+ return audioBuffer; >+} >+ >+// For the record, these distance formulas were taken from the OpenAL >+// spec, not the code. >+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 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; >+} >+ >+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; >+} >+ >+// This array must be arranged in the numeric order of the distance >+// model values. >+var distanceModelFunction = [linearDistance, inverseDistance, exponentialDistance]; >+ >+function createGraph(context, distanceModel, nodeCount) { >+ // Create all the sources, which are impulses. >+ bufferSource = new Array(nodeCount); >+ for (var k = 0; k < nodeCount; ++k) { >+ bufferSource[k] = context.createBufferSource(); >+ impulse = createImpulseBuffer(context, pulseLengthFrames); >+ bufferSource[k].buffer = impulse; >+ } >+ >+ // Create all the panners. >+ panner = new Array(nodeCount); >+ position = new Array(nodeCount); >+ var angleStep = Math.PI / nodeCount; >+ for (var k = 0; k < nodeCount; ++k) { >+ panner[k] = context.createPanner(); >+ panner[k].panningModel = panner.EQUALPOWER; >+ panner[k].distanceModel = distanceModel; >+ // The position is the angle uniformly spaced between 0 and 180 >+ // deg, but we want to avoid 0 because the equal power panner will >+ // produce 0 which messes up our check routine. >+ position[k] = angleStep * (k + 1/2); >+ panner[k].setPosition(Math.cos(position[k]), 0, Math.sin(position[k])); >+ } >+ >+ // Connect the sources and panners. >+ for (var k = 0; k < nodeCount; ++k) { >+ bufferSource[k].connect(panner[k]); >+ panner[k].connect(context.destination); >+ } >+} >+ >+function startSources() { >+ // Turn on each source at uniform intervals. >+ time = new Array(nodesToCreate); >+ for (var k = 0; k < nodesToCreate; ++k) { >+ time[k] = k * timeStep; >+ bufferSource[k].noteOn(time[k]); >+ } >+} >+ >+function createTestAndRun(context, distanceModel, pannerModel, nodes, threshold) { >+ createGraph(context, distanceModel, nodes); >+ startSources(); >+ >+ context.oncomplete = checkResult(pannerModel, threshold, false); >+ context.startRendering(); >+} >+ >+// Normalize a vector to unit length. >+function normalize(v) { >+ var length = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); >+ return {x : v.x / length, y : v.y / length, z : v.z / length}; >+} >+ >+// Vector dot product between v1 and v2. >+function dot(v1, v2) { >+ return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; >+} >+ >+// Vector cross product a X b. >+function cross(a, b) { >+ return {x : a.y * b.z - a.z * b.y, >+ y : a.z * b.x - a.x * b.z, >+ z : a.x * b.y - a.y * b.x}; >+} >+ >+// Vector difference: a - b >+function sub(a, b) { >+ return {x : a.x - b.x, y : a.y - b.y, z : a.z - b.z}; >+} >+ >+// Scale a vector v by the scalar value s. >+function scalarMult(s, v) { >+ return {x : s * v.x, y : s * v.y, z : s * v.z}; >+} >+ >+function getAzimuth(angle) { >+ // Compute the azimuth. See getAzimuthElevation in AudioPannerNode.cpp. >+ // >+ // Should we remove this complicated computation? The default >+ // values for everything allow most of this to be removed, but we >+ // include this just to be sure we compute the azimuth correctly. >+ var listenerPosition = {x : 0, y : 0, z : 0}; >+ var sourceListener = sub({x : Math.cos(angle), y : 0, z : Math.sin(angle)}, >+ listenerPosition); >+ var listenerFront = {x : 0, y : 0, z : -1}; >+ var listenerUp = {x : 0, y : 1, z : 0}; >+ var listenerRight = cross(listenerFront, listenerUp); >+ listenerRight = normalize(listenerRight); >+ var listenerFrontNorm = normalize(listenerFront); >+ var up = cross(listenerRight, listenerFrontNorm); >+ var upProjection = dot(sourceListener, up); >+ var projectedSource = normalize(sub(sourceListener, scalarMult(upProjection, up))); >+ >+ var azimuth = 180 * Math.acos(dot(projectedSource, listenerRight)) / Math.PI; >+ var frontBack = dot(projectedSource, listenerFrontNorm); >+ >+ if (frontBack < 0) { >+ azimuth = 360 - azimuth; >+ } >+ if ((azimuth >= 0) && (azimuth <= 270)) { >+ azimuth = 90 - azimuth; >+ } else { >+ azimuth = 450 - azimuth; >+ } >+ return azimuth; >+} >+ >+// The gain caused by the EQUALPOWER panning model >+function equalPowerGain(angle) { >+ var azimuth = getAzimuth(angle); >+ >+ if (azimuth < -90) { >+ azimuth = -180 - azimuth; >+ } else if (azimuth > 90) { >+ azimuth = 180 - azimuth; >+ } >+ >+ var panPosition = (azimuth + 90)/180; >+ >+ var gainL = Math.cos(0.5 * Math.PI * panPosition); >+ var gainR = Math.sin(0.5 * Math.PI * panPosition); >+ >+ return { left : gainL, right : gainR }; >+} >+ >+function checkResult(model, threshold, debug) { >+ return function(event) { >+ renderedBuffer = event.renderedBuffer; >+ renderedLeft = renderedBuffer.getChannelData(0); >+ renderedRight = renderedBuffer.getChannelData(1); >+ >+ var success = true; >+ // Number of impulses found in the rendered result. >+ var impulseCount = 0; >+ // Max (relative) error and the index of the maxima for the left >+ // and right channels. >+ var maxErrorL = 0; >+ var maxErrorIndexL = 0; >+ var maxErrorR = 0; >+ var maxErrorIndexR = 0; >+ // Number of impulses that don't match our expected locations. >+ // (For debugging). >+ var timeCount = 0; >+ // Locations of where the impulses aren't at the expected locations. >+ var timeErrors = new Array(); >+ >+ for (var k = 0; k < renderedLeft.length; ++k) { >+ // We assume that the left and right channels start at the same instance. >+ if (renderedLeft[k] != 0) { >+ var dFunction = distanceModelFunction[panner[impulseCount].distanceModel]; >+ var dGain = dFunction(panner[impulseCount], >+ Math.cos(position[impulseCount]), >+ 0, >+ Math.sin(position[impulseCount])); >+ >+ // The expected gain for the left and right channels. >+ var expectedL = dGain * equalPowerGain(position[impulseCount]).left; >+ var expectedR = dGain * equalPowerGain(position[impulseCount]).right; >+ >+ // Relative error in the gain. >+ var errorL = Math.abs(renderedLeft[k] - expectedL)/Math.abs(expectedL); >+ var errorR = Math.abs(renderedRight[k] - expectedR)/Math.abs(expectedR); >+ if (debug) { >+ console.log("Left: " + k + ": " + renderedLeft[k] + " (expected " + expectedL + ", rel = ", errorL + ")"); >+ console.log("Right: " + k + ": " + renderedRight[k] + " (expected " + expectedR + ", rel = ", errorR + ")"); >+ } >+ if (Math.abs(errorL) > maxErrorL) { >+ maxErrorL = Math.abs(errorL); >+ maxErrorIndexL = impulseCount; >+ } >+ if (Math.abs(errorR) > maxErrorR) { >+ maxErrorR = Math.abs(errorR); >+ maxErrorIndexR = impulseCount; >+ } >+ >+ // For debugging. Keep track of the impulses that didn't show >+ // up where we expected them to be. >+ if (k != Math.round(sampleRate * time[impulseCount])) { >+ timeErrors[timeCount] = { actual : k, expected : Math.round(sampleRate * time[impulseCount])}; >+ ++timeCount; >+ } >+ ++impulseCount; >+ } >+ } >+ >+ if (impulseCount == nodesToCreate) { >+ testPassed("Number of nodes is correct."); >+ } else { >+ testFailed("Number of nodes is incorrect. (Found " + impulseCount + " but expected " + nodesToCreate + ")"); >+ success = false; >+ } >+ >+ if (maxErrorL <= threshold) { >+ testPassed("Left channel panner values are correct."); >+ } else { >+ testFailed("Left channel panner values are incorrect. Max rel error = " + maxErrorL + " at time " + maxErrorIndexL / sampleRate + " (threshold = " + threshold + ")"); >+ success = false; >+ } >+ if (maxErrorR <= threshold) { >+ testPassed("Right channel panner values are correct."); >+ } else { >+ testFailed("Right channel panner values are incorrect. Max rel error = " + maxErrorR + " at time " + maxErrorIndexR / sampleRate + " (threshold = " + threshold + ")"); >+ success = false; >+ } >+ >+ // for debugging. It seems that some impulses don't show up at >+ // exactly the expected rendered location. Log these to the >+ // console if debugging is true. >+ // >+ // FIXME: File a bug report on this. >+ if (debug && timeErrors.length > 0) { >+ console.log(timeErrors.length + " timing errors found"); >+ for (var k = 0; k < timeErrors.length; ++k) { >+ console.log("Sample " + timeErrors[k].actual + " but expected " + timeErrors[k].expected); >+ } >+ } >+ >+ if (success) { >+ testPassed("EqualPower panner test passed for panner model " + model); >+ } else { >+ testFailed("EqualPower panner test failed for panner model " + model); >+ } >+ >+ finishJSTest(); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 75767
:
121684
|
121864
|
122082
|
122318
|
122332
|
122335
|
122439
|
122464