Bug 1156472 - Part 13 - Make necessary adjustments for integer audio. r=jesup
authorPaul Adenot <paul@paul.cx>
Fri, 24 Jul 2015 14:28:17 +0200
changeset 286427 4351b1e432dd4a412f705adbaf7afeab89d0ce25
parent 286426 4c62be998cb40ab77296993113b181ace7374b9f
child 286428 7d3b6dcae7fe1b7f81d155444af1b28070264f5a
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1156472
milestone42.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 1156472 - Part 13 - Make necessary adjustments for integer audio. r=jesup
dom/media/AudioChannelFormat.cpp
dom/media/AudioChannelFormat.h
dom/media/AudioSegment.cpp
--- a/dom/media/AudioChannelFormat.cpp
+++ b/dom/media/AudioChannelFormat.cpp
@@ -1,34 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioChannelFormat.h"
-#include "nsTArray.h"
 
 #include <algorithm>
 
 namespace mozilla {
 
-enum {
-  SURROUND_L,
-  SURROUND_R,
-  SURROUND_C,
-  SURROUND_LFE,
-  SURROUND_SL,
-  SURROUND_SR
-};
-
-static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6;
-
-static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS;
-static const float IGNORE_F = 0.0f;
-
 uint32_t
 GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
 {
   return std::max(aChannels1, aChannels2);
 }
 
 /**
  * UpMixMatrix represents a conversion matrix by exploiting the fact that
@@ -58,19 +43,16 @@ gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(C
   { { 0, 1, 2, IGNORE, IGNORE, IGNORE } },
   // Upmixes from quad
   { { 0, 1, 2, 3, IGNORE } },
   { { 0, 1, IGNORE, IGNORE, 2, 3 } },
   // Upmixes from 5-channel
   { { 0, 1, 2, 3, 4, IGNORE } }
 };
 
-static const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
-  { 0, 5, 9, 12, 14 };
-
 void
 AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
                    uint32_t aOutputChannelCount,
                    const void* aZeroChannel)
 {
   uint32_t inputChannelCount = aChannelArray->Length();
   uint32_t outputChannelCount =
     GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
@@ -103,99 +85,9 @@ AudioChannelsUpMix(nsTArray<const void*>
     return;
   }
 
   for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
     aChannelArray->ElementAt(i) = aZeroChannel;
   }
 }
 
-/**
- * DownMixMatrix represents a conversion matrix efficiently by exploiting the
- * fact that each input channel contributes to at most one output channel,
- * except possibly for the C input channel in layouts that have one. Also,
- * every input channel is multiplied by the same coefficient for every output
- * channel it contributes to.
- */
-struct DownMixMatrix {
-  // Every input channel c is copied to output channel mInputDestination[c]
-  // after multiplying by mInputCoefficient[c].
-  uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
-  // If not IGNORE, then the C channel is copied to this output channel after
-  // multiplying by its coefficient.
-  uint8_t mCExtraDestination;
-  float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS];
-};
-
-static const DownMixMatrix
-gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
-{
-  // Downmixes to mono
-  { { 0, 0 }, IGNORE, { 0.5f, 0.5f } },
-  { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } },
-  { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
-  { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } },
-  { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } },
-  // Downmixes to stereo
-  { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } },
-  { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } },
-  { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
-  { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } },
-  // Downmixes to 3-channel
-  { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } },
-  { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } },
-  { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
-  // Downmixes to quad
-  { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } },
-  { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } },
-  // Downmixes to 5-channel
-  { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }
-};
-
-void
-AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
-                     float** aOutputChannels,
-                     uint32_t aOutputChannelCount,
-                     uint32_t aDuration)
-{
-  uint32_t inputChannelCount = aChannelArray.Length();
-  const void* const* inputChannels = aChannelArray.Elements();
-  NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
-
-  if (inputChannelCount > 6) {
-    // Just drop the unknown channels.
-    for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
-      memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float));
-    }
-    return;
-  }
-
-  // Ignore unknown channels, they're just dropped.
-  inputChannelCount = std::min<uint32_t>(6, inputChannelCount);
-
-  const DownMixMatrix& m = gDownMixMatrices[
-    gMixingMatrixIndexByChannels[aOutputChannelCount - 1] +
-    inputChannelCount - aOutputChannelCount - 1];
-
-  // This is slow, but general. We can define custom code for special
-  // cases later.
-  for (uint32_t s = 0; s < aDuration; ++s) {
-    // Reserve an extra junk channel at the end for the cases where we
-    // want an input channel to contribute to nothing
-    float outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1];
-    memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS));
-    for (uint32_t c = 0; c < inputChannelCount; ++c) {
-      outputChannels[m.mInputDestination[c]] +=
-        m.mInputCoefficient[c]*(static_cast<const float*>(inputChannels[c]))[s];
-    }
-    // Utilize the fact that in every layout, C is the third channel.
-    if (m.mCExtraDestination != IGNORE) {
-      outputChannels[m.mCExtraDestination] +=
-        m.mInputCoefficient[SURROUND_C]*(static_cast<const float*>(inputChannels[SURROUND_C]))[s];
-    }
-
-    for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
-      aOutputChannels[c][s] = outputChannels[c];
-    }
-  }
-}
-
 } // namespace mozilla
--- a/dom/media/AudioChannelFormat.h
+++ b/dom/media/AudioChannelFormat.h
@@ -4,16 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef MOZILLA_AUDIOCHANNELFORMAT_H_
 #define MOZILLA_AUDIOCHANNELFORMAT_H_
 
 #include <stdint.h>
 
 #include "nsTArrayForwardDeclare.h"
+#include "AudioSampleFormat.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 
 /*
  * This file provides utilities for upmixing and downmixing channels.
  *
  * The channel layouts, upmixing and downmixing are consistent with the
  * Web Audio spec.
@@ -24,16 +26,36 @@ namespace mozilla {
  *          { L, R, C }
  *   quad   { L, R, SL, SR }
  *          { L, R, C, SL, SR }
  *   5.1    { L, R, C, LFE, SL, SR }
  *
  * Only 1, 2, 4 and 6 are currently defined in Web Audio.
  */
 
+enum {
+  SURROUND_L,
+  SURROUND_R,
+  SURROUND_C,
+  SURROUND_LFE,
+  SURROUND_SL,
+  SURROUND_SR
+};
+
+const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6;
+
+// This is defined by some Windows SDK header.
+#undef IGNORE
+
+const int IGNORE = CUSTOM_CHANNEL_LAYOUTS;
+const float IGNORE_F = 0.0f;
+
+const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
+  { 0, 5, 9, 12, 14 };
+
 /**
  * Return a channel count whose channel layout includes all the channels from
  * aChannels1 and aChannels2.
  */
 uint32_t
 GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2);
 
 /**
@@ -48,25 +70,108 @@ GetAudioChannelsSuperset(uint32_t aChann
  * GetAudioChannelsSuperset calls resulting in aOutputChannelCount,
  * no downmixing will be required.
  */
 void
 AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
                    uint32_t aOutputChannelCount,
                    const void* aZeroChannel);
 
+
 /**
- * Given an array of input channels (which must be float format!),
- * downmix to aOutputChannelCount, and copy the results to the
- * channel buffers in aOutputChannels.
- * Don't call this with input count <= output count.
+ * DownMixMatrix represents a conversion matrix efficiently by exploiting the
+ * fact that each input channel contributes to at most one output channel,
+ * except possibly for the C input channel in layouts that have one. Also,
+ * every input channel is multiplied by the same coefficient for every output
+ * channel it contributes to.
+ */
+struct DownMixMatrix {
+  // Every input channel c is copied to output channel mInputDestination[c]
+  // after multiplying by mInputCoefficient[c].
+  uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
+  // If not IGNORE, then the C channel is copied to this output channel after
+  // multiplying by its coefficient.
+  uint8_t mCExtraDestination;
+  float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS];
+};
+
+static const DownMixMatrix
+gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
+{
+  // Downmixes to mono
+  { { 0, 0 }, IGNORE, { 0.5f, 0.5f } },
+  { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } },
+  { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
+  { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } },
+  { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } },
+  // Downmixes to stereo
+  { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } },
+  { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } },
+  { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
+  { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } },
+  // Downmixes to 3-channel
+  { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } },
+  { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } },
+  { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
+  // Downmixes to quad
+  { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } },
+  { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } },
+  // Downmixes to 5-channel
+  { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }
+};
+
+/**
+ * Given an array of input channels, downmix to aOutputChannelCount, and copy
+ * the results to the channel buffers in aOutputChannels.  Don't call this with
+ * input count <= output count.
  */
-void
-AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
-                     float** aOutputChannels,
+template<typename T>
+void AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
+                     T** aOutputChannels,
                      uint32_t aOutputChannelCount,
-                     uint32_t aDuration);
+                     uint32_t aDuration)
+{
+  uint32_t inputChannelCount = aChannelArray.Length();
+  const void* const* inputChannels = aChannelArray.Elements();
+  NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
+
+  if (inputChannelCount > 6) {
+    // Just drop the unknown channels.
+    for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
+      memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(T));
+    }
+    return;
+  }
+
+  // Ignore unknown channels, they're just dropped.
+  inputChannelCount = std::min<uint32_t>(6, inputChannelCount);
+
+  const DownMixMatrix& m = gDownMixMatrices[
+    gMixingMatrixIndexByChannels[aOutputChannelCount - 1] +
+    inputChannelCount - aOutputChannelCount - 1];
 
-// A version of AudioChannelsDownMix that downmixes int16_ts may be required.
+  // This is slow, but general. We can define custom code for special
+  // cases later.
+  for (uint32_t s = 0; s < aDuration; ++s) {
+    // Reserve an extra junk channel at the end for the cases where we
+    // want an input channel to contribute to nothing
+    T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1];
+    memset(outputChannels, 0, sizeof(T)*(CUSTOM_CHANNEL_LAYOUTS));
+    for (uint32_t c = 0; c < inputChannelCount; ++c) {
+      outputChannels[m.mInputDestination[c]] +=
+        m.mInputCoefficient[c]*(static_cast<const T*>(inputChannels[c]))[s];
+    }
+    // Utilize the fact that in every layout, C is the third channel.
+    if (m.mCExtraDestination != IGNORE) {
+      outputChannels[m.mCExtraDestination] +=
+        m.mInputCoefficient[SURROUND_C]*(static_cast<const T*>(inputChannels[SURROUND_C]))[s];
+    }
+
+    for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
+      aOutputChannels[c][s] = outputChannels[c];
+    }
+  }
+}
+
 
 } // namespace mozilla
 
 #endif /* MOZILLA_AUDIOCHANNELFORMAT_H_ */
--- a/dom/media/AudioSegment.cpp
+++ b/dom/media/AudioSegment.cpp
@@ -201,39 +201,39 @@ AudioSegment::Mix(AudioMixer& aMixer, ui
       }
       if (channelData.Length() < aOutputChannels) {
         // Up-mix.
         AudioChannelsUpMix(&channelData, aOutputChannels, gZeroChannel);
         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
           AudioDataValue* ptr =
             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
                                       aOutputChannels, channel, offsetSamples);
-          PodCopy(ptr, reinterpret_cast<const float*>(channelData[channel]),
+          PodCopy(ptr, reinterpret_cast<const AudioDataValue*>(channelData[channel]),
                   frames);
         }
         MOZ_ASSERT(channelData.Length() == aOutputChannels);
       } else if (channelData.Length() > aOutputChannels) {
         // Down mix.
-        nsAutoTArray<float*, GUESS_AUDIO_CHANNELS> outChannelPtrs;
+        nsAutoTArray<AudioDataValue*, GUESS_AUDIO_CHANNELS> outChannelPtrs;
         outChannelPtrs.SetLength(aOutputChannels);
         uint32_t offsetSamples = 0;
         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
           outChannelPtrs[channel] =
             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
                                       aOutputChannels, channel, offsetSamples);
         }
         AudioChannelsDownMix(channelData, outChannelPtrs.Elements(),
                              aOutputChannels, frames);
       } else {
         // The channel count is already what we want, just copy it over.
         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
           AudioDataValue* ptr =
             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
                                       aOutputChannels, channel, offsetSamples);
-          PodCopy(ptr, reinterpret_cast<const float*>(channelData[channel]),
+          PodCopy(ptr, reinterpret_cast<const AudioDataValue*>(channelData[channel]),
                   frames);
         }
       }
     }
     offsetSamples += frames;
   }
 
   if (offsetSamples) {