LCOV - code coverage report
Current view: top level - dom/media - AudioChannelFormat.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 41 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : #ifndef MOZILLA_AUDIOCHANNELFORMAT_H_
       7             : #define MOZILLA_AUDIOCHANNELFORMAT_H_
       8             : 
       9             : #include <stdint.h>
      10             : 
      11             : #include "nsTArrayForwardDeclare.h"
      12             : #include "AudioSampleFormat.h"
      13             : #include "nsTArray.h"
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : /*
      18             :  * This file provides utilities for upmixing and downmixing channels.
      19             :  *
      20             :  * The channel layouts, upmixing and downmixing are consistent with the
      21             :  * Web Audio spec.
      22             :  *
      23             :  * Channel layouts for up to 6 channels:
      24             :  *   mono   { M }
      25             :  *   stereo { L, R }
      26             :  *          { L, R, C }
      27             :  *   quad   { L, R, SL, SR }
      28             :  *          { L, R, C, SL, SR }
      29             :  *   5.1    { L, R, C, LFE, SL, SR }
      30             :  *
      31             :  * Only 1, 2, 4 and 6 are currently defined in Web Audio.
      32             :  */
      33             : 
      34             : enum {
      35             :   SURROUND_L,
      36             :   SURROUND_R,
      37             :   SURROUND_C,
      38             :   SURROUND_LFE,
      39             :   SURROUND_SL,
      40             :   SURROUND_SR
      41             : };
      42             : 
      43             : const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6;
      44             : 
      45             : // This is defined by some Windows SDK header.
      46             : #undef IGNORE
      47             : 
      48             : const int IGNORE = CUSTOM_CHANNEL_LAYOUTS;
      49             : const float IGNORE_F = 0.0f;
      50             : 
      51             : const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
      52             :   { 0, 5, 9, 12, 14 };
      53             : 
      54             : /**
      55             :  * Return a channel count whose channel layout includes all the channels from
      56             :  * aChannels1 and aChannels2.
      57             :  */
      58             : uint32_t
      59             : GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2);
      60             : 
      61             : /**
      62             :  * DownMixMatrix represents a conversion matrix efficiently by exploiting the
      63             :  * fact that each input channel contributes to at most one output channel,
      64             :  * except possibly for the C input channel in layouts that have one. Also,
      65             :  * every input channel is multiplied by the same coefficient for every output
      66             :  * channel it contributes to.
      67             :  */
      68             : const float SQRT_ONE_HALF = 0.7071067811865476f;
      69             : 
      70             : struct DownMixMatrix {
      71             :   // Every input channel c is copied to output channel mInputDestination[c]
      72             :   // after multiplying by mInputCoefficient[c].
      73             :   uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
      74             :   // If not IGNORE, then the C channel is copied to this output channel after
      75             :   // multiplying by its coefficient.
      76             :   uint8_t mCExtraDestination;
      77             :   float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS];
      78             : };
      79             : 
      80             : static const DownMixMatrix
      81             : gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
      82             : {
      83             :   // Downmixes to mono
      84             :   { { 0, 0 }, IGNORE, { 0.5f, 0.5f } },
      85             :   { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } },
      86             :   { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
      87             :   { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } },
      88             :   { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { SQRT_ONE_HALF, SQRT_ONE_HALF, 1.0f, IGNORE_F, 0.5f, 0.5f } },
      89             :   // Downmixes to stereo
      90             :   { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } },
      91             :   { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } },
      92             :   { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
      93             :   { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, SQRT_ONE_HALF, IGNORE_F, SQRT_ONE_HALF, SQRT_ONE_HALF } },
      94             :   // Downmixes to 3-channel
      95             :   { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } },
      96             :   { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } },
      97             :   { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
      98             :   // Downmixes to quad
      99             :   { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } },
     100             :   { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, SQRT_ONE_HALF, IGNORE_F, 1.0f, 1.0f } },
     101             :   // Downmixes to 5-channel
     102             :   { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }
     103             : };
     104             : 
     105             : /**
     106             :  * Given an array of input channels, downmix to aOutputChannelCount, and copy
     107             :  * the results to the channel buffers in aOutputChannels.  Don't call this with
     108             :  * input count <= output count.
     109             :  */
     110             : template<typename T>
     111           0 : void AudioChannelsDownMix(const nsTArray<const T*>& aChannelArray,
     112             :                           T** aOutputChannels,
     113             :                           uint32_t aOutputChannelCount,
     114             :                           uint32_t aDuration)
     115             : {
     116           0 :   uint32_t inputChannelCount = aChannelArray.Length();
     117           0 :   const T* const* inputChannels = aChannelArray.Elements();
     118           0 :   NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
     119             : 
     120           0 :   if (inputChannelCount > 6) {
     121             :     // Just drop the unknown channels.
     122           0 :     for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
     123           0 :       PodCopy(aOutputChannels[o], inputChannels[o], aDuration);
     124             :     }
     125           0 :     return;
     126             :   }
     127             : 
     128             :   // Ignore unknown channels, they're just dropped.
     129           0 :   inputChannelCount = std::min<uint32_t>(6, inputChannelCount);
     130             : 
     131             :   const DownMixMatrix& m = gDownMixMatrices[
     132           0 :     gMixingMatrixIndexByChannels[aOutputChannelCount - 1] +
     133           0 :     inputChannelCount - aOutputChannelCount - 1];
     134             : 
     135             :   // This is slow, but general. We can define custom code for special
     136             :   // cases later.
     137           0 :   for (uint32_t s = 0; s < aDuration; ++s) {
     138             :     // Reserve an extra junk channel at the end for the cases where we
     139             :     // want an input channel to contribute to nothing
     140           0 :     T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1] = {0};
     141           0 :     for (uint32_t c = 0; c < inputChannelCount; ++c) {
     142           0 :       outputChannels[m.mInputDestination[c]] +=
     143           0 :         m.mInputCoefficient[c]*(static_cast<const T*>(inputChannels[c]))[s];
     144             :     }
     145             :     // Utilize the fact that in every layout, C is the third channel.
     146           0 :     if (m.mCExtraDestination != IGNORE) {
     147           0 :       outputChannels[m.mCExtraDestination] +=
     148           0 :         m.mInputCoefficient[SURROUND_C]*(static_cast<const T*>(inputChannels[SURROUND_C]))[s];
     149             :     }
     150             : 
     151           0 :     for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
     152           0 :       aOutputChannels[c][s] = outputChannels[c];
     153             :     }
     154             :   }
     155             : }
     156             : 
     157             : /**
     158             :  * UpMixMatrix represents a conversion matrix by exploiting the fact that
     159             :  * each output channel comes from at most one input channel.
     160             :  */
     161             : struct UpMixMatrix {
     162             :   uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
     163             : };
     164             : 
     165             : static const UpMixMatrix
     166             : gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
     167             : {
     168             :   // Upmixes from mono
     169             :   { { 0, 0 } },
     170             :   { { 0, IGNORE, IGNORE } },
     171             :   { { 0, 0, IGNORE, IGNORE } },
     172             :   { { 0, IGNORE, IGNORE, IGNORE, IGNORE } },
     173             :   { { IGNORE, IGNORE, 0, IGNORE, IGNORE, IGNORE } },
     174             :   // Upmixes from stereo
     175             :   { { 0, 1, IGNORE } },
     176             :   { { 0, 1, IGNORE, IGNORE } },
     177             :   { { 0, 1, IGNORE, IGNORE, IGNORE } },
     178             :   { { 0, 1, IGNORE, IGNORE, IGNORE, IGNORE } },
     179             :   // Upmixes from 3-channel
     180             :   { { 0, 1, 2, IGNORE } },
     181             :   { { 0, 1, 2, IGNORE, IGNORE } },
     182             :   { { 0, 1, 2, IGNORE, IGNORE, IGNORE } },
     183             :   // Upmixes from quad
     184             :   { { 0, 1, 2, 3, IGNORE } },
     185             :   { { 0, 1, IGNORE, IGNORE, 2, 3 } },
     186             :   // Upmixes from 5-channel
     187             :   { { 0, 1, 2, 3, 4, IGNORE } }
     188             : };
     189             : 
     190             : 
     191             : /**
     192             :  * Given an array of input channel data, and an output channel count,
     193             :  * replaces the array with an array of upmixed channels.
     194             :  * This shuffles the array and may set some channel buffers to aZeroChannel.
     195             :  * Don't call this with input count >= output count.
     196             :  * This may return *more* channels than requested. In that case, downmixing
     197             :  * is required to to get to aOutputChannelCount. (This is how we handle
     198             :  * odd cases like 3 -> 4 upmixing.)
     199             :  * If aChannelArray.Length() was the input to one of a series of
     200             :  * GetAudioChannelsSuperset calls resulting in aOutputChannelCount,
     201             :  * no downmixing will be required.
     202             :  */
     203             : template<typename T>
     204             : void
     205           0 : AudioChannelsUpMix(nsTArray<const T*>* aChannelArray,
     206             :                    uint32_t aOutputChannelCount,
     207             :                    const T* aZeroChannel)
     208             : {
     209           0 :   uint32_t inputChannelCount = aChannelArray->Length();
     210             :   uint32_t outputChannelCount =
     211           0 :     GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
     212           0 :   NS_ASSERTION(outputChannelCount > inputChannelCount,
     213             :                "No up-mix needed");
     214           0 :   MOZ_ASSERT(inputChannelCount > 0, "Bad number of channels");
     215           0 :   MOZ_ASSERT(outputChannelCount > 0, "Bad number of channels");
     216             : 
     217           0 :   aChannelArray->SetLength(outputChannelCount);
     218             : 
     219           0 :   if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS &&
     220             :       outputChannelCount <= CUSTOM_CHANNEL_LAYOUTS) {
     221             :     const UpMixMatrix& m = gUpMixMatrices[
     222           0 :       gMixingMatrixIndexByChannels[inputChannelCount - 1] +
     223           0 :       outputChannelCount - inputChannelCount - 1];
     224             : 
     225             :     const T* outputChannels[CUSTOM_CHANNEL_LAYOUTS];
     226             : 
     227           0 :     for (uint32_t i = 0; i < outputChannelCount; ++i) {
     228           0 :       uint8_t channelIndex = m.mInputDestination[i];
     229           0 :       if (channelIndex == IGNORE) {
     230           0 :         outputChannels[i] = aZeroChannel;
     231             :       } else {
     232           0 :         outputChannels[i] = aChannelArray->ElementAt(channelIndex);
     233             :       }
     234             :     }
     235           0 :     for (uint32_t i = 0; i < outputChannelCount; ++i) {
     236           0 :       aChannelArray->ElementAt(i) = outputChannels[i];
     237             :     }
     238           0 :     return;
     239             :   }
     240             : 
     241           0 :   for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
     242           0 :     aChannelArray->ElementAt(i) = aZeroChannel;
     243             :   }
     244             : }
     245             : 
     246             : } // namespace mozilla
     247             : 
     248             : #endif /* MOZILLA_AUDIOCHANNELFORMAT_H_ */

Generated by: LCOV version 1.13