Title: [133101] trunk
Revision
133101
Author
[email protected]
Date
2012-10-31 17:39:39 -0700 (Wed, 31 Oct 2012)

Log Message

Implement optional arguments in AudioBufferSourceNode start() method
https://bugs.webkit.org/show_bug.cgi?id=100894

Reviewed by Kenneth Russell.

Source/WebCore:

The start() method should be able to take 1, 2, or 3 arguments, optionally supporting
offset and duration.  Currently, only 1 and 3 arguments are supported.

Test: webaudio/audiobuffersource-start.html

* Modules/webaudio/AudioBufferSourceNode.cpp:
(WebCore::AudioBufferSourceNode::renderFromBuffer):
(WebCore::AudioBufferSourceNode::startGrain):
(WebCore):
* Modules/webaudio/AudioBufferSourceNode.h:
(AudioBufferSourceNode):
* Modules/webaudio/AudioBufferSourceNode.idl:

LayoutTests:

* webaudio/audiobuffersource-loop-comprehensive.html:
* webaudio/audiobuffersource-start-expected.txt: Added.
* webaudio/audiobuffersource-start.html: Added.
* webaudio/resources/audiobuffersource-testing.js: Added.
(createTestBuffer):
(checkSingleTest):
(checkAllTests):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (133100 => 133101)


--- trunk/LayoutTests/ChangeLog	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/LayoutTests/ChangeLog	2012-11-01 00:39:39 UTC (rev 133101)
@@ -1,3 +1,18 @@
+2012-10-31  Chris Rogers  <[email protected]>
+
+        Implement optional arguments in AudioBufferSourceNode start() method
+        https://bugs.webkit.org/show_bug.cgi?id=100894
+
+        Reviewed by Kenneth Russell.
+
+        * webaudio/audiobuffersource-loop-comprehensive.html:
+        * webaudio/audiobuffersource-start-expected.txt: Added.
+        * webaudio/audiobuffersource-start.html: Added.
+        * webaudio/resources/audiobuffersource-testing.js: Added.
+        (createTestBuffer):
+        (checkSingleTest):
+        (checkAllTests):
+
 2012-10-31  Stephen White  <[email protected]>
 
         [Chromium] Unreviewed gardening.

Modified: trunk/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html (133100 => 133101)


--- trunk/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html	2012-11-01 00:39:39 UTC (rev 133101)
@@ -4,6 +4,7 @@
 <head>
 <link rel="stylesheet" href=""
 <script src=""
+<script src=""
 <script src=""
 </head>
 
@@ -69,17 +70,6 @@
 var testSpacingSeconds = testSpacingFrames / sampleRate;
 var totalRenderLengthFrames = tests.length * testSpacingFrames;
 
-function createTestBuffer(context, sampleFrameLength) {
-    var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate);
-    var channelData = audioBuffer.getChannelData(0);
-
-    // Create a simple linear ramp starting at zero, with each value in the buffer equal to its index position.
-    for (var i = 0; i < sampleFrameLength; ++i)
-        channelData[i] = i;
-
-    return audioBuffer;
-}
-
 function runLoopTest(context, testNumber, test) {
     var source = context.createBufferSource();
 
@@ -98,45 +88,6 @@
     source.stop(startTime + duration);
 }
 
-function checkSingleTest(renderedBuffer, i) {
-    var renderedData = renderedBuffer.getChannelData(0);
-    var offsetFrame = i * testSpacingFrames;
-
-    var test = tests[i];
-    var description = test.description;
-    var expected = test.expected;
-
-    var success = true;
-
-    for (var j = 0; j < test.renderFrames; ++j) {
-        if (expected[j] != renderedData[offsetFrame + j]) {
-            // Copy from Float32Array to regular _javascript_ array for error message.
-            var renderedArray = new Array();
-            for (var j = 0; j < test.renderFrames; ++j)
-                renderedArray[j] = renderedData[offsetFrame + j];
-
-            var s = description + ": expected: " + expected + " actual: " + renderedArray;
-            testFailed(s);
-            success = false;
-            break;
-        }
-    }
-
-    if (success)
-        testPassed(description);
-
-    return success;
-}
-
-function checkLoopResults(event) {
-    var renderedBuffer = event.renderedBuffer;
-    for (var i = 0; i < tests.length; ++i)
-        checkSingleTest(renderedBuffer, i);
-
-    if (window.testRunner)
-        testRunner.notifyDone()
-}
-
 function runTest() {
     if (window.testRunner) {
         testRunner.dumpAsText();
@@ -152,7 +103,7 @@
     for (var i = 0; i < tests.length; ++i)
         runLoopTest(context, i, tests[i]);
 
-    context._oncomplete_ = checkLoopResults;
+    context._oncomplete_ = checkAllTests;
     context.startRendering();
 }
 

Added: trunk/LayoutTests/webaudio/audiobuffersource-start-expected.txt (0 => 133101)


--- trunk/LayoutTests/webaudio/audiobuffersource-start-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-start-expected.txt	2012-11-01 00:39:39 UTC (rev 133101)
@@ -0,0 +1,10 @@
+Tests AudioBufferSourceNode start() with a variety of offsets and durations.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS start(when): implicitly play whole buffer from beginning to end
+PASS start(when, 0): play whole buffer from beginning to end explicitly giving offset of 0
+PASS start(when, 0, 8_frames): play whole buffer from beginning to end explicitly giving offset of 0 and duration of 8 frames
+PASS start(when, 4_frames): play with explicit non-zero offset
+PASS start(when, 4_frames, 4_frames): play with explicit non-zero offset and duration
+

Added: trunk/LayoutTests/webaudio/audiobuffersource-start.html (0 => 133101)


--- trunk/LayoutTests/webaudio/audiobuffersource-start.html	                        (rev 0)
+++ trunk/LayoutTests/webaudio/audiobuffersource-start.html	2012-11-01 00:39:39 UTC (rev 133101)
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<link rel="stylesheet" href=""
+<script src=""
+<script src=""
+<script src=""
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("Tests AudioBufferSourceNode start() with a variety of offsets and durations.");
+
+// The following test cases assume an AudioBuffer of length 8 whose PCM data is a linear ramp, 0, 1, 2, 3,...
+
+var tests = [
+
+{ description: "start(when): implicitly play whole buffer from beginning to end",
+  offsetFrame: "none", durationFrames: "none", renderFrames: 16, playbackRate: 1, expected: [0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0] },
+
+{ description: "start(when, 0): play whole buffer from beginning to end explicitly giving offset of 0",
+  offsetFrame: 0, durationFrames: "none", renderFrames: 16, playbackRate: 1, expected: [0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0] },
+
+{ description: "start(when, 0, 8_frames): play whole buffer from beginning to end explicitly giving offset of 0 and duration of 8 frames",
+  offsetFrame: 0, durationFrames: 8, renderFrames: 16, playbackRate: 1, expected: [0,1,2,3,4,5,6,7,0,0,0,0,0,0,0,0] },
+
+{ description: "start(when, 4_frames): play with explicit non-zero offset",
+  offsetFrame: 4, durationFrames: "none", renderFrames: 16, playbackRate: 1, expected: [4,5,6,7,0,0,0,0,0,0,0,0,0,0,0,0] },
+
+{ description: "start(when, 4_frames, 4_frames): play with explicit non-zero offset and duration",
+  offsetFrame: 4, durationFrames: 4, renderFrames: 16, playbackRate: 1, expected: [4,5,6,7,0,0,0,0,0,0,0,0,0,0,0,0] },
+
+// Enable test when AudioBufferSourceNode hack is fixed: https://bugs.webkit.org/show_bug.cgi?id=77224
+// { description: "start(when, 3_frames, 3_frames): play a middle section with explicit offset and duration",
+//   offsetFrame: 3, durationFrames: 3, renderFrames: 16, playbackRate: 1, expected: [4,5,6,7,0,0,0,0,0,0,0,0,0,0,0,0] },
+
+];
+
+var sampleRate = 44100;
+var buffer;
+var bufferFrameLength = 8;
+var testSpacingFrames = 32;
+var testSpacingSeconds = testSpacingFrames / sampleRate;
+var totalRenderLengthFrames = tests.length * testSpacingFrames;
+
+function runLoopTest(context, testNumber, test) {
+    var source = context.createBufferSource();
+
+    source.buffer = buffer;
+    source.playbackRate.value = test.playbackRate;
+
+    source.connect(context.destination);
+
+    // Render each test one after the other, spaced apart by testSpacingSeconds.
+    var startTime = testNumber * testSpacingSeconds;
+
+    if (test.offsetFrame == "none" && test.durationFrames == "none") {
+        source.start(startTime);
+    } else if (test.durationFrames == "none") {
+        var offset = test.offsetFrame / context.sampleRate;
+        source.start(startTime, offset);
+    } else {
+        var offset = test.offsetFrame / context.sampleRate;
+        var duration = test.durationFrames / context.sampleRate;
+        source.start(startTime, offset, duration);
+    }
+}
+
+function runTest() {
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    window.jsTestIsAsync = true;
+
+    // Create offline audio context.
+    var context = new webkitAudioContext(1, totalRenderLengthFrames, sampleRate);
+    buffer = createTestBuffer(context, bufferFrameLength);
+
+    for (var i = 0; i < tests.length; ++i)
+        runLoopTest(context, i, tests[i]);
+
+    context._oncomplete_ = checkAllTests;
+    context.startRendering();
+}
+
+runTest();
+successfullyParsed = true;
+
+</script>
+
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js (0 => 133101)


--- trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js	                        (rev 0)
+++ trunk/LayoutTests/webaudio/resources/audiobuffersource-testing.js	2012-11-01 00:39:39 UTC (rev 133101)
@@ -0,0 +1,49 @@
+function createTestBuffer(context, sampleFrameLength) {
+    var audioBuffer = context.createBuffer(1, sampleFrameLength, context.sampleRate);
+    var channelData = audioBuffer.getChannelData(0);
+
+    // Create a simple linear ramp starting at zero, with each value in the buffer equal to its index position.
+    for (var i = 0; i < sampleFrameLength; ++i)
+        channelData[i] = i;
+
+    return audioBuffer;
+}
+
+function checkSingleTest(renderedBuffer, i) {
+    var renderedData = renderedBuffer.getChannelData(0);
+    var offsetFrame = i * testSpacingFrames;
+
+    var test = tests[i];
+    var description = test.description;
+    var expected = test.expected;
+
+    var success = true;
+
+    for (var j = 0; j < test.renderFrames; ++j) {
+        if (expected[j] != renderedData[offsetFrame + j]) {
+            // Copy from Float32Array to regular _javascript_ array for error message.
+            var renderedArray = new Array();
+            for (var j = 0; j < test.renderFrames; ++j)
+                renderedArray[j] = renderedData[offsetFrame + j];
+
+            var s = description + ": expected: " + expected + " actual: " + renderedArray;
+            testFailed(s);
+            success = false;
+            break;
+        }
+    }
+
+    if (success)
+        testPassed(description);
+
+    return success;
+}
+
+function checkAllTests(event) {
+    var renderedBuffer = event.renderedBuffer;
+    for (var i = 0; i < tests.length; ++i)
+        checkSingleTest(renderedBuffer, i);
+
+    if (window.testRunner)
+        testRunner.notifyDone()
+}

Modified: trunk/Source/WebCore/ChangeLog (133100 => 133101)


--- trunk/Source/WebCore/ChangeLog	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/Source/WebCore/ChangeLog	2012-11-01 00:39:39 UTC (rev 133101)
@@ -1,3 +1,23 @@
+2012-10-31  Chris Rogers  <[email protected]>
+
+        Implement optional arguments in AudioBufferSourceNode start() method
+        https://bugs.webkit.org/show_bug.cgi?id=100894
+
+        Reviewed by Kenneth Russell.
+
+        The start() method should be able to take 1, 2, or 3 arguments, optionally supporting
+        offset and duration.  Currently, only 1 and 3 arguments are supported.
+
+        Test: webaudio/audiobuffersource-start.html
+
+        * Modules/webaudio/AudioBufferSourceNode.cpp:
+        (WebCore::AudioBufferSourceNode::renderFromBuffer):
+        (WebCore::AudioBufferSourceNode::startGrain):
+        (WebCore):
+        * Modules/webaudio/AudioBufferSourceNode.h:
+        (AudioBufferSourceNode):
+        * Modules/webaudio/AudioBufferSourceNode.idl:
+
 2012-10-31  Mike West  <[email protected]>
 
         Implement the canonical "Content-Security-Policy" header.

Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp (133100 => 133101)


--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.cpp	2012-11-01 00:39:39 UTC (rev 133101)
@@ -195,35 +195,26 @@
     size_t bufferLength = buffer()->length();
     double bufferSampleRate = buffer()->sampleRate();
 
-    // Calculate the start and end frames in our buffer that we want to play.
-    // If m_isGrain is true, then we will be playing a portion of the total buffer.
-    unsigned startFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset, bufferSampleRate) : 0;
-
     // Avoid converting from time to sample-frames twice by computing
     // the grain end time first before computing the sample frame.
     unsigned endFrame = m_isGrain ? AudioUtilities::timeToSampleFrame(m_grainOffset + m_grainDuration, bufferSampleRate) : bufferLength;
     
-    ASSERT(endFrame >= startFrame);
-    if (endFrame < startFrame)
-        return false;
-    
     // This is a HACK to allow for HRTF tail-time - avoids glitch at end.
     // FIXME: implement tailTime for each AudioNode for a more general solution to this problem.
+    // https://bugs.webkit.org/show_bug.cgi?id=77224
     if (m_isGrain)
         endFrame += 512;
 
     // Do some sanity checking.
-    if (startFrame >= bufferLength)
-        startFrame = !bufferLength ? 0 : bufferLength - 1;
     if (endFrame > bufferLength)
         endFrame = bufferLength;
     if (m_virtualReadIndex >= endFrame)
-        m_virtualReadIndex = startFrame; // reset to start
+        m_virtualReadIndex = 0; // reset to start
 
     // If the .loop attribute is true, then values of m_loopStart == 0 && m_loopEnd == 0 implies
     // that we should use the entire buffer as the loop, otherwise use the loop values in m_loopStart and m_loopEnd.
     double virtualEndFrame = endFrame;
-    double virtualDeltaFrames = endFrame - startFrame;
+    double virtualDeltaFrames = endFrame;
 
     if (loop() && (m_loopStart || m_loopEnd) && m_loopStart >= 0 && m_loopEnd > 0 && m_loopStart < m_loopEnd) {
         // Convert from seconds to sample-frames.
@@ -234,6 +225,7 @@
         virtualDeltaFrames = virtualEndFrame - loopStartFrame;
     }
 
+
     double pitchRate = totalPitchRate();
 
     // Sanity check that our playback rate isn't larger than the loop size.
@@ -372,6 +364,12 @@
     return output(0)->numberOfChannels();
 }
 
+void AudioBufferSourceNode::startGrain(double when, double grainOffset)
+{
+    // Duration of 0 has special value, meaning calculate based on the entire buffer's duration.
+    startGrain(when, grainOffset, 0);
+}
+
 void AudioBufferSourceNode::startGrain(double when, double grainOffset, double grainDuration)
 {
     ASSERT(isMainThread());
@@ -385,21 +383,22 @@
     // Do sanity checking of grain parameters versus buffer size.
     double bufferDuration = buffer()->duration();
 
-    if (grainDuration > bufferDuration)
-        return; // FIXME: maybe should throw exception - consider in specification.
-    
-    double maxGrainOffset = bufferDuration - grainDuration;
-    maxGrainOffset = max(0.0, maxGrainOffset);
-
     grainOffset = max(0.0, grainOffset);
-    grainOffset = min(maxGrainOffset, grainOffset);
+    grainOffset = min(bufferDuration, grainOffset);
     m_grainOffset = grainOffset;
 
+    // Handle default/unspecified duration.
+    double maxDuration = bufferDuration - grainOffset;
+    if (!grainDuration)
+        grainDuration = maxDuration;
+
+    grainDuration = max(0.0, grainDuration);
+    grainDuration = min(maxDuration, grainDuration);
     m_grainDuration = grainDuration;
-    
+
     m_isGrain = true;
     m_startTime = when;
-
+    
     // We call timeToSampleFrame here since at playbackRate == 1 we don't want to go through linear interpolation
     // at a sub-sample position since it will degrade the quality.
     // When aligned to the sample-frame the playback will be identical to the PCM data stored in the buffer.

Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h (133100 => 133101)


--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.h	2012-11-01 00:39:39 UTC (rev 133101)
@@ -62,6 +62,7 @@
     unsigned numberOfChannels();
                     
     // Play-state
+    void startGrain(double when, double grainOffset);
     void startGrain(double when, double grainOffset, double grainDuration);
 
 #if ENABLE(LEGACY_WEB_AUDIO)

Modified: trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl (133100 => 133101)


--- trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl	2012-11-01 00:31:14 UTC (rev 133100)
+++ trunk/Source/WebCore/Modules/webaudio/AudioBufferSourceNode.idl	2012-11-01 00:39:39 UTC (rev 133101)
@@ -46,6 +46,7 @@
     attribute double loopEnd;
 
     [V8MeasureAs=WebAudioStart] void start(in double when);
+    [V8MeasureAs=WebAudioStart, ImplementedAs=startGrain] void start(in double when, in double grainOffset);
     [V8MeasureAs=WebAudioStart, ImplementedAs=startGrain] void start(in double when, in double grainOffset, in double grainDuration);
     void stop(in double when);
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to