AudioBus need to support stereo->mono down mix in copyFrom sumFrom etc.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Feb 2012 23:00:32 +0000 (23:00 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Feb 2012 23:00:32 +0000 (23:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=77609

Patch by Wei James <james.wei@intel.com> on 2012-02-06
Reviewed by Kenneth Russell.

Test: webaudio/stereo2mono-down-mixing.html

* platform/audio/AudioBus.cpp:
(WebCore):
(WebCore::AudioBus::copyFrom):
(WebCore::AudioBus::sumFrom):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@106858 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/webaudio/stereo2mono-down-mixing-expected.txt [new file with mode: 0644]
LayoutTests/webaudio/stereo2mono-down-mixing.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/audio/AudioBus.cpp

diff --git a/LayoutTests/webaudio/stereo2mono-down-mixing-expected.txt b/LayoutTests/webaudio/stereo2mono-down-mixing-expected.txt
new file mode 100644 (file)
index 0000000..96b28cc
--- /dev/null
@@ -0,0 +1,9 @@
+This test verifies whether down mixing from stereo to mono will cause assertion error.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS Test no ASSERT error.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/webaudio/stereo2mono-down-mixing.html b/LayoutTests/webaudio/stereo2mono-down-mixing.html
new file mode 100644 (file)
index 0000000..56b22d0
--- /dev/null
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<script src="../fast/js/resources/js-test-pre.js"></script>
+</head>
+
+<body>
+
+<div id="description"></div>
+<div id="console"></div>
+
+<script>
+description("This test verifies whether down mixing from stereo to mono will cause assertion error.");
+
+var sampleRate = 44100.0;
+var renderLengthSeconds = 0.1;
+var fftSize = 32;
+
+var context;
+var toneBuffer;
+var bufferSource;
+var analyser;
+
+function createDataBuffer(context, lengthInSeconds) {
+    var audioBuffer = context.createBuffer(1, lengthInSeconds * sampleRate, sampleRate);
+
+    var n = audioBuffer.length;
+    var data = audioBuffer.getChannelData(0);
+
+    for (var i = 0; i < n; ++i) {
+        data[i] = 1.0;
+    }
+
+    return audioBuffer;
+}
+
+function testFinished() {
+    testPassed("Test no ASSERT error.");
+    finishJSTest();
+}
+
+function runTest() {
+    if (window.layoutTestController) {
+        layoutTestController.overridePreference("WebKitWebAudioEnabled", "1");
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    window.jsTestIsAsync = true;
+
+    // Create offline audio context.
+    context = new webkitAudioContext(1, sampleRate * renderLengthSeconds, sampleRate);
+    // Explicitly create a mono AudioContext so that the destination is mono.
+    toneBuffer = createDataBuffer(context, renderLengthSeconds);
+
+    bufferSource = context.createBufferSource();
+    bufferSource.buffer = toneBuffer;
+
+    // We create an analyser here, because it has a hard-coded stereo output.
+    analyser = context.createAnalyser();
+    analyser.fftSize = fftSize;
+
+    bufferSource.connect(analyser);
+    analyser.connect(context.destination);
+
+    bufferSource.noteOn(0);
+
+    context.oncomplete = testFinished;
+    context.startRendering();
+}
+
+
+runTest();
+
+</script>
+
+<script src="../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 1e0b9ba..860e5de 100644 (file)
@@ -1,3 +1,17 @@
+2012-02-06  Wei James  <james.wei@intel.com>
+
+        AudioBus need to support stereo->mono down mix in copyFrom sumFrom etc.
+        https://bugs.webkit.org/show_bug.cgi?id=77609
+
+        Reviewed by Kenneth Russell.
+
+        Test: webaudio/stereo2mono-down-mixing.html
+
+        * platform/audio/AudioBus.cpp:
+        (WebCore):
+        (WebCore::AudioBus::copyFrom):
+        (WebCore::AudioBus::sumFrom):
+
 2012-02-06  Cris Neckar  <cdn@chromium.org>
 
         Add RefPtrs for parent and sibling counter nodes
index eea1919..d6aa350 100644 (file)
@@ -196,21 +196,35 @@ void AudioBus::scale(float scale)
 
 // Just copies the samples from the source bus to this one.
 // This is just a simple copy if the number of channels match, otherwise a mixup or mixdown is done.
-// For now, we just support a mixup from mono -> stereo.
+// For now, we just support mixup from mono -> stereo and mixdown from stereo -> mono.
 void AudioBus::copyFrom(const AudioBus& sourceBus)
 {
     if (&sourceBus == this)
         return;
 
-    if (numberOfChannels() == sourceBus.numberOfChannels()) {
-        for (unsigned i = 0; i < numberOfChannels(); ++i)
+    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
+    unsigned numberOfDestinationChannels = numberOfChannels();
+
+    if (numberOfDestinationChannels == numberOfSourceChannels) {
+        for (unsigned i = 0; i < numberOfSourceChannels; ++i)
             channel(i)->copyFrom(sourceBus.channel(i));
-    } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+    } else if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) {
         // Handle mono -> stereo case (for now simply copy mono channel into both left and right)
         // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
         const AudioChannel* sourceChannel = sourceBus.channel(0);
         channel(0)->copyFrom(sourceChannel);
         channel(1)->copyFrom(sourceChannel);
+    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
+        // Handle stereo -> mono case. output = 0.5 * (input.L + input.R).
+        AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
+
+        const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
+        const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data();
+
+        float* destination = channelByType(ChannelLeft)->mutableData();
+        vadd(sourceL, 1, sourceR, 1, destination, 1, length());
+        float scale = 0.5;
+        vsmul(destination, 1, &scale, destination, 1, length());
     } else {
         // Case not handled
         ASSERT_NOT_REACHED();
@@ -219,15 +233,29 @@ void AudioBus::copyFrom(const AudioBus& sourceBus)
 
 void AudioBus::sumFrom(const AudioBus &sourceBus)
 {
-    if (numberOfChannels() == sourceBus.numberOfChannels()) {
+    unsigned numberOfSourceChannels = sourceBus.numberOfChannels();
+    unsigned numberOfDestinationChannels = numberOfChannels();
+
+    if (numberOfDestinationChannels == numberOfSourceChannels) {
         for (unsigned i = 0; i < numberOfChannels(); ++i)
             channel(i)->sumFrom(sourceBus.channel(i));
-    } else if (numberOfChannels() == 2 && sourceBus.numberOfChannels() == 1) {
+    } else if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) {
         // Handle mono -> stereo case (for now simply sum mono channel into both left and right)
         // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center...
         const AudioChannel* sourceChannel = sourceBus.channel(0);
         channel(0)->sumFrom(sourceChannel);
         channel(1)->sumFrom(sourceChannel);
+    } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) {
+        // Handle stereo -> mono case. output += 0.5 * (input.L + input.R).
+        AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus);
+
+        const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data();
+        const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data();
+
+        float* destination = channelByType(ChannelLeft)->mutableData();
+        float scale = 0.5;
+        vsma(sourceL, 1, &scale, destination, 1, length());
+        vsma(sourceR, 1, &scale, destination, 1, length());
     } else {
         // Case not handled
         ASSERT_NOT_REACHED();