Bug 1500238 correct mono-to-stereo panning at centre position r=padenot
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 19 Oct 2018 09:25:27 +0000
changeset 442203 01b1f806550b9a8c610c653b842305e1f3e9ad3a
parent 442202 17f777b161890b63b207c412549e4afc7129fa32
child 442204 75d951d7f8acedb2ebd986a4b8668d0bc54f2515
push id34890
push userdvarga@mozilla.com
push dateSat, 20 Oct 2018 09:40:11 +0000
treeherdermozilla-central@d0f1450799b5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1500238
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1500238 correct mono-to-stereo panning at centre position r=padenot and re-use input buffer instead of copying. Depends on D9211 Differential Revision: https://phabricator.services.mozilla.com/D9212
dom/media/webaudio/AudioBlock.h
dom/media/webaudio/PannerNode.cpp
dom/media/webaudio/PanningUtils.h
dom/media/webaudio/StereoPannerNode.cpp
--- a/dom/media/webaudio/AudioBlock.h
+++ b/dom/media/webaudio/AudioBlock.h
@@ -41,17 +41,17 @@ public:
   using AudioChunk::GetDuration;
   using AudioChunk::IsNull;
   using AudioChunk::IsAudible;
   using AudioChunk::ChannelCount;
   using AudioChunk::ChannelData;
   using AudioChunk::SizeOfExcludingThisIfUnshared;
   using AudioChunk::SizeOfExcludingThis;
   // mDuration is not exposed.  Use GetDuration().
-  // mBuffer is not exposed.  Use SetBuffer().
+  // mBuffer is not exposed.  Use Get/SetBuffer().
   using AudioChunk::mChannelData;
   using AudioChunk::mVolume;
   using AudioChunk::mBufferFormat;
 
   const AudioChunk& AsAudioChunk() const { return *this; }
   AudioChunk* AsMutableChunk() {
     ClearDownstreamMark();
     return this;
@@ -69,16 +69,17 @@ public:
    */
   float* ChannelFloatsForWrite(size_t aChannel)
   {
     MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
     MOZ_ASSERT(CanWrite());
     return static_cast<float*>(const_cast<void*>(mChannelData[aChannel]));
   }
 
+  ThreadSharedObject* GetBuffer() const { return mBuffer; }
   void SetBuffer(ThreadSharedObject* aNewBuffer);
   void SetNull(StreamTime aDuration) {
     MOZ_ASSERT(aDuration == WEBAUDIO_BLOCK_SIZE);
     SetBuffer(nullptr);
     mChannelData.Clear();
     mVolume = 1.0f;
     mBufferFormat = AUDIO_FORMAT_SILENCE;
   }
--- a/dom/media/webaudio/PannerNode.cpp
+++ b/dom/media/webaudio/PannerNode.cpp
@@ -457,19 +457,16 @@ PannerNodeEngine::EqualPowerPanningFunct
     // For a stereo source, when both the listener and the panner are in
     // the same spot, and no cone gain is specified, this node is noop.
     if (inputChannels == 2 && mListenerEngine->Position() == position &&
         mConeInnerAngle == 360 && mConeOuterAngle == 360) {
       *aOutput = aInput;
       return;
     }
 
-    // The output of this node is always stereo, no matter what the inputs are.
-    aOutput->AllocateChannels(2);
-
     ComputeAzimuthAndElevation(position, azimuth, elevation);
     coneGain = ComputeConeGain(position, orientation);
 
     // The following algorithm is described in the spec.
     // Clamp azimuth in the [-90, 90] range.
     azimuth = min(180.f, max(-180.f, azimuth));
 
     // Wrap around
@@ -503,19 +500,16 @@ PannerNodeEngine::EqualPowerPanningFunct
   } else {
     float positionX[WEBAUDIO_BLOCK_SIZE];
     float positionY[WEBAUDIO_BLOCK_SIZE];
     float positionZ[WEBAUDIO_BLOCK_SIZE];
     float orientationX[WEBAUDIO_BLOCK_SIZE];
     float orientationY[WEBAUDIO_BLOCK_SIZE];
     float orientationZ[WEBAUDIO_BLOCK_SIZE];
 
-    // The output of this node is always stereo, no matter what the inputs are.
-    aOutput->AllocateChannels(2);
-
     if (!mPositionX.HasSimpleValue()) {
       mPositionX.GetValuesAtTime(tick, positionX, WEBAUDIO_BLOCK_SIZE);
     } else {
       positionX[0] = mPositionX.GetValueAtTime(tick);
     }
     if (!mPositionY.HasSimpleValue()) {
       mPositionY.GetValuesAtTime(tick, positionY, WEBAUDIO_BLOCK_SIZE);
     } else {
--- a/dom/media/webaudio/PanningUtils.h
+++ b/dom/media/webaudio/PanningUtils.h
@@ -47,16 +47,18 @@ GainStereoToStereo(const AudioBlock& aIn
 }
 
 // T can be float or an array of float, and  U can be bool or an array of bool,
 // depending if the value of the parameters are constant for this block.
 template<typename T, typename U>
 void ApplyStereoPanning(const AudioBlock& aInput, AudioBlock* aOutput,
                         T aGainL, T aGainR, U aOnLeft)
 {
+  aOutput->AllocateChannels(2);
+
   if (aInput.ChannelCount() == 1) {
     GainMonoToStereo(aInput, aOutput, aGainL, aGainR);
   } else {
     GainStereoToStereo(aInput, aOutput, aGainL, aGainR, aOnLeft);
   }
 }
 
 } // namespace dom
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -87,26 +87,28 @@ public:
         samples[i] = 0.f;
       }
     }
   }
 
   void UpmixToStereoIfNeeded(const AudioBlock& aInput, AudioBlock* aOutput)
   {
     if (aInput.ChannelCount() == 2) {
-      const float* inputL = static_cast<const float*>(aInput.mChannelData[0]);
-      const float* inputR = static_cast<const float*>(aInput.mChannelData[1]);
-      float* outputL = aOutput->ChannelFloatsForWrite(0);
-      float* outputR = aOutput->ChannelFloatsForWrite(1);
-
-      AudioBlockCopyChannelWithScale(inputL, aInput.mVolume, outputL);
-      AudioBlockCopyChannelWithScale(inputR, aInput.mVolume, outputR);
+      *aOutput = aInput;
     } else {
       MOZ_ASSERT(aInput.ChannelCount() == 1);
-      GainMonoToStereo(aInput, aOutput, aInput.mVolume, aInput.mVolume);
+      aOutput->SetBuffer(aInput.GetBuffer());
+      aOutput->mChannelData.SetLength(2);
+      for (uint32_t i = 0; i < 2; ++i) {
+        aOutput->mChannelData[i] = aInput.ChannelData<float>()[0];
+      }
+      // 1/sqrt(2) multiplier is because StereoPanner up-mixing differs from
+      // input up-mixing.
+      aOutput->mVolume = M_SQRT1_2 * aInput.mVolume;
+      aOutput->mBufferFormat = AUDIO_FORMAT_FLOAT32;
     }
   }
 
   virtual void ProcessBlock(AudioNodeStream* aStream,
                             GraphTime aFrom,
                             const AudioBlock& aInput,
                             AudioBlock* aOutput,
                             bool *aFinished) override
@@ -114,17 +116,16 @@ public:
     // The output of this node is always stereo, no matter what the inputs are.
     MOZ_ASSERT(aInput.ChannelCount() <= 2);
     bool monoToStereo = aInput.ChannelCount() == 1;
 
     if (aInput.IsNull()) {
       // If input is silent, so is the output
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
     } else if (mPan.HasSimpleValue()) {
-      aOutput->AllocateChannels(2);
       float panning = mPan.GetValue();
       // If the panning is 0.0, we can simply copy the input to the
       // output with gain applied, up-mixing to stereo if needed.
       if (panning == 0.0f) {
         UpmixToStereoIfNeeded(aInput, aOutput);
       } else {
         // Optimize the case where the panning is constant for this processing
         // block: we can just apply a constant gain on the left and right
@@ -133,17 +134,16 @@ public:
 
         GetGainValuesForPanning(panning, monoToStereo, gainL, gainR);
         ApplyStereoPanning(aInput, aOutput,
                            gainL * aInput.mVolume,
                            gainR * aInput.mVolume,
                            panning <= 0);
       }
     } else {
-      aOutput->AllocateChannels(2);
       float computedGain[2*WEBAUDIO_BLOCK_SIZE + 4];
       bool onLeft[WEBAUDIO_BLOCK_SIZE];
 
       float values[WEBAUDIO_BLOCK_SIZE];
       StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
       mPan.GetValuesAtTime(tick, values, WEBAUDIO_BLOCK_SIZE);
 
       float* alignedComputedGain = ALIGNED16(computedGain);