Bug 1276483 - Fix WaveShaper when connected from a silent GainNode; r?padenot draft
authorDan Minor <dminor@mozilla.com>
Mon, 20 Jun 2016 10:42:50 -0400
changeset 380095 08aecc1ae07f3fcef4d038cf1cfc662013e667ba
parent 379985 3c5025f98e561a20e24d97c91a9e4e0ec28015ea
child 523643 fb23a911ec7f6b726bc8937527451996a7b42aee
push id21136
push userdminor@mozilla.com
push dateMon, 20 Jun 2016 17:25:49 +0000
reviewerspadenot
bugs1276483
milestone50.0a1
Bug 1276483 - Fix WaveShaper when connected from a silent GainNode; r?padenot MozReview-Commit-ID: CUEO6PDwo5B
dom/media/webaudio/WaveShaperNode.cpp
dom/media/webaudio/test/test_waveShaperGain.html
--- a/dom/media/webaudio/WaveShaperNode.cpp
+++ b/dom/media/webaudio/WaveShaperNode.cpp
@@ -217,37 +217,58 @@ public:
 
   void ProcessBlock(AudioNodeStream* aStream,
                     GraphTime aFrom,
                     const AudioBlock& aInput,
                     AudioBlock* aOutput,
                     bool* aFinished) override
   {
     uint32_t channelCount = aInput.ChannelCount();
-    if (!mCurve.Length() || !channelCount) {
-      // Optimize the case where we don't have a curve buffer,
-      // or the input is null.
+    if (!mCurve.Length()) {
+      // Optimize the case where we don't have a curve buffer
       *aOutput = aInput;
       return;
     }
 
+    // If the input is null, check to see if non-null output will be produced
+    bool nullInput = false;
+    if (channelCount == 0) {
+      float index = (mCurve.Length() - 1) * 0.5;
+      uint32_t indexLower = index;
+      uint32_t indexHigher = indexLower + 1;
+      float interpolationFactor = index - indexLower;
+      if ((1.0f - interpolationFactor) * mCurve[indexLower] +
+          interpolationFactor * mCurve[indexHigher] == 0.0) {
+        *aOutput = aInput;
+        return;
+      } else {
+        nullInput = true;
+        channelCount = 1;
+      }
+    }
+
     aOutput->AllocateChannels(channelCount);
     for (uint32_t i = 0; i < channelCount; ++i) {
       const float* inputSamples;
       float scaledInput[WEBAUDIO_BLOCK_SIZE + 4];
       float* alignedScaledInput = ALIGNED16(scaledInput);
       ASSERT_ALIGNED16(alignedScaledInput);
-      if (aInput.mVolume != 1.0f) {
-        AudioBlockCopyChannelWithScale(
-            static_cast<const float*>(aInput.mChannelData[i]),
-                                      aInput.mVolume,
-                                      alignedScaledInput);
+      if (!nullInput) {
+        if (aInput.mVolume != 1.0f) {
+          AudioBlockCopyChannelWithScale(
+              static_cast<const float*>(aInput.mChannelData[i]),
+                                        aInput.mVolume,
+                                        alignedScaledInput);
+          inputSamples = alignedScaledInput;
+        } else {
+          inputSamples = static_cast<const float*>(aInput.mChannelData[i]);
+        }
+      } else {
+        PodZero(alignedScaledInput);
         inputSamples = alignedScaledInput;
-      } else {
-        inputSamples = static_cast<const float*>(aInput.mChannelData[i]);
       }
       float* outputBuffer = aOutput->ChannelFloatsForWrite(i);
       float* sampleBuffer;
 
       switch (mType) {
       case OverSampleType::None:
         mResampler.Reset(channelCount, aStream->SampleRate(), OverSampleType::None);
         ProcessCurve<1>(inputSamples, outputBuffer);
--- a/dom/media/webaudio/test/test_waveShaperGain.html
+++ b/dom/media/webaudio/test/test_waveShaperGain.html
@@ -37,15 +37,36 @@ for (var i = 0; i < 2; i++) {
 dc.connect(gain);
 dc.start();
 
 gain.gain.value = 0.5;
 
 context.startRendering().then(buffer => {
   document.querySelector("pre").innerHTML = buffer.getChannelData(0)[0];
   ok(buffer.getChannelData(0)[0] == 1.0, "Volume was handled properly");
-  SimpleTest.finish();
+
+  context = new OfflineAudioContext(1, 100, samplerate);
+  var oscillator = context.createOscillator();
+  var gain = context.createGain();
+  var waveShaper = context.createWaveShaper();
+
+  oscillator.start(0);
+  oscillator.connect(gain);
+
+  // to silence
+  gain.gain.value = 0;
+  gain.connect(waveShaper);
+
+  // convert all signal into 1.0
+  waveShaper.curve = new Float32Array([ 1, 1 ]);
+  waveShaper.connect(context.destination);
+
+  context.startRendering().then((buffer) => {
+    var result = buffer.getChannelData(0);
+    ok(result.every(x => x === 1), "WaveShaper handles zero gain properly");
+    SimpleTest.finish();
+  });
 });
 </script>
 <pre>
 </pre>
 </body>