tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

channel_mixing_matrix_unittest.cc (15742B)


      1 /*
      2 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "audio/utility/channel_mixing_matrix.h"
     12 
     13 #include <cstddef>
     14 #include <vector>
     15 
     16 #include "api/audio/channel_layout.h"
     17 #include "audio/utility/channel_mixer.h"
     18 #include "rtc_base/strings/string_builder.h"
     19 #include "test/gtest.h"
     20 
     21 namespace webrtc {
     22 
     23 // Test all possible layout conversions can be constructed and mixed.
     24 // Also ensure that the channel matrix fulfill certain conditions when remapping
     25 // is supported.
     26 TEST(ChannelMixingMatrixTest, ConstructAllPossibleLayouts) {
     27  for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
     28       input_layout <= CHANNEL_LAYOUT_MAX;
     29       input_layout = static_cast<ChannelLayout>(input_layout + 1)) {
     30    for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
     31         output_layout <= CHANNEL_LAYOUT_MAX;
     32         output_layout = static_cast<ChannelLayout>(output_layout + 1)) {
     33      // DISCRETE, BITSTREAM can't be tested here based on the current approach.
     34      // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable.
     35      // Stereo down mix should never be the output layout.
     36      if (input_layout == CHANNEL_LAYOUT_BITSTREAM ||
     37          input_layout == CHANNEL_LAYOUT_DISCRETE ||
     38          input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
     39          output_layout == CHANNEL_LAYOUT_BITSTREAM ||
     40          output_layout == CHANNEL_LAYOUT_DISCRETE ||
     41          output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC ||
     42          output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) {
     43        continue;
     44      }
     45 
     46      StringBuilder ss;
     47      ss << "Input Layout: " << input_layout
     48         << ", Output Layout: " << output_layout;
     49      SCOPED_TRACE(ss.str());
     50      ChannelMixingMatrix matrix_builder(
     51          input_layout, ChannelLayoutToChannelCount(input_layout),
     52          output_layout, ChannelLayoutToChannelCount(output_layout));
     53      const int input_channels = ChannelLayoutToChannelCount(input_layout);
     54      const int output_channels = ChannelLayoutToChannelCount(output_layout);
     55      std::vector<std::vector<float>> matrix;
     56      bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
     57 
     58      if (remapping) {
     59        // Also ensure that (when remapping can take place), a maximum of one
     60        // input channel is included per output. This knowledge will simplify
     61        // the channel mixing algorithm since it allows us to find the only
     62        // scale factor which equals 1.0 and copy that input to its
     63        // corresponding output. If no such factor can be found, the
     64        // corresponding output can be set to zero.
     65        for (int i = 0; i < output_channels; i++) {
     66          EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
     67          int num_input_channels_accounted_for_per_output = 0;
     68          for (int j = 0; j < input_channels; j++) {
     69            float scale = matrix[i][j];
     70            if (scale > 0) {
     71              EXPECT_EQ(scale, 1.0f);
     72              num_input_channels_accounted_for_per_output++;
     73            }
     74          }
     75          // Each output channel shall contain contribution from one or less
     76          // input channels.
     77          EXPECT_LE(num_input_channels_accounted_for_per_output, 1);
     78        }
     79      }
     80    }
     81  }
     82 }
     83 
     84 // Verify channels are mixed and scaled correctly.
     85 TEST(ChannelMixingMatrixTest, StereoToMono) {
     86  ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
     87  ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
     88  ChannelMixingMatrix matrix_builder(
     89      input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
     90      ChannelLayoutToChannelCount(output_layout));
     91  std::vector<std::vector<float>> matrix;
     92  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
     93 
     94  //                      Input: stereo
     95  //                      LEFT  RIGHT
     96  // Output: mono CENTER  0.5   0.5
     97  //
     98  EXPECT_FALSE(remapping);
     99  EXPECT_EQ(1u, matrix.size());
    100  EXPECT_EQ(2u, matrix[0].size());
    101  EXPECT_EQ(0.5f, matrix[0][0]);
    102  EXPECT_EQ(0.5f, matrix[0][1]);
    103 }
    104 
    105 TEST(ChannelMixingMatrixTest, MonoToStereo) {
    106  ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
    107  ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
    108  ChannelMixingMatrix matrix_builder(
    109      input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
    110      ChannelLayoutToChannelCount(output_layout));
    111  std::vector<std::vector<float>> matrix;
    112  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    113 
    114  //                       Input: mono
    115  //                       CENTER
    116  // Output: stereo LEFT   1
    117  //                RIGHT  1
    118  //
    119  EXPECT_TRUE(remapping);
    120  EXPECT_EQ(2u, matrix.size());
    121  EXPECT_EQ(1u, matrix[0].size());
    122  EXPECT_EQ(1.0f, matrix[0][0]);
    123  EXPECT_EQ(1u, matrix[1].size());
    124  EXPECT_EQ(1.0f, matrix[1][0]);
    125 }
    126 
    127 TEST(ChannelMixingMatrixTest, MonoToTwoOne) {
    128  ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
    129  ChannelLayout output_layout = CHANNEL_LAYOUT_2_1;
    130  ChannelMixingMatrix matrix_builder(
    131      input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
    132      ChannelLayoutToChannelCount(output_layout));
    133  std::vector<std::vector<float>> matrix;
    134  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    135 
    136  //                         Input: mono
    137  //                         CENTER
    138  // Output: 2.1 FRONT_LEFT  1
    139  //             FRONT_RIGHT 1
    140  //             BACK_CENTER 0
    141  //
    142  EXPECT_TRUE(remapping);
    143  EXPECT_EQ(3u, matrix.size());
    144  EXPECT_EQ(1u, matrix[0].size());
    145  EXPECT_EQ(1.0f, matrix[0][0]);
    146  EXPECT_EQ(1.0f, matrix[1][0]);
    147  EXPECT_EQ(0.0f, matrix[2][0]);
    148 }
    149 
    150 TEST(ChannelMixingMatrixTest, MonoToFiveOne) {
    151  ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
    152  ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
    153  const int input_channels = ChannelLayoutToChannelCount(input_layout);
    154  const int output_channels = ChannelLayoutToChannelCount(output_layout);
    155  ChannelMixingMatrix matrix_builder(input_layout, input_channels,
    156                                     output_layout, output_channels);
    157  std::vector<std::vector<float>> matrix;
    158  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    159  //                         Input: mono
    160  //                         CENTER
    161  // Output: 5.1 LEFT        1
    162  //             RIGHT       1
    163  //             CENTER      0
    164  //             LFE         0
    165  //             SIDE_LEFT   0
    166  //             SIDE_RIGHT  0
    167  //
    168  EXPECT_TRUE(remapping);
    169  EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    170  for (int n = 0; n < output_channels; n++) {
    171    EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
    172    if (n == LEFT || n == RIGHT) {
    173      EXPECT_EQ(1.0f, matrix[n][0]);
    174    } else {
    175      EXPECT_EQ(0.0f, matrix[n][0]);
    176    }
    177  }
    178 }
    179 
    180 TEST(ChannelMixingMatrixTest, MonoToSevenOne) {
    181  ChannelLayout input_layout = CHANNEL_LAYOUT_MONO;
    182  ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
    183  const int input_channels = ChannelLayoutToChannelCount(input_layout);
    184  const int output_channels = ChannelLayoutToChannelCount(output_layout);
    185  ChannelMixingMatrix matrix_builder(input_layout, input_channels,
    186                                     output_layout, output_channels);
    187  std::vector<std::vector<float>> matrix;
    188  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    189  //                         Input: mono
    190  //                         CENTER
    191  // Output: 7.1 LEFT        1
    192  //             RIGHT       1
    193  //             CENTER      0
    194  //             LFE         0
    195  //             SIDE_LEFT   0
    196  //             SIDE_RIGHT  0
    197  //             BACK_LEFT   0
    198  //             BACK_RIGHT  0
    199  //
    200  EXPECT_TRUE(remapping);
    201  EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    202  for (int n = 0; n < output_channels; n++) {
    203    EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
    204    if (n == LEFT || n == RIGHT) {
    205      EXPECT_EQ(1.0f, matrix[n][0]);
    206    } else {
    207      EXPECT_EQ(0.0f, matrix[n][0]);
    208    }
    209  }
    210 }
    211 
    212 TEST(ChannelMixingMatrixTest, FiveOneToMono) {
    213  ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
    214  ChannelLayout output_layout = CHANNEL_LAYOUT_MONO;
    215  ChannelMixingMatrix matrix_builder(
    216      input_layout, ChannelLayoutToChannelCount(input_layout), output_layout,
    217      ChannelLayoutToChannelCount(output_layout));
    218  std::vector<std::vector<float>> matrix;
    219  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    220 
    221  // Note: 1/sqrt(2) is shown as 0.707.
    222  //
    223  //                      Input: 5.1
    224  //                      LEFT   RIGHT  CENTER  LFE    SIDE_LEFT  SIDE_RIGHT
    225  // Output: mono CENTER  0.707  0.707  1       0.707  0.707      0.707
    226  //
    227  EXPECT_FALSE(remapping);
    228  EXPECT_EQ(1u, matrix.size());
    229  EXPECT_EQ(6u, matrix[0].size());
    230  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][0]);
    231  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][1]);
    232  // The center channel will be mixed at scale 1.
    233  EXPECT_EQ(1.0f, matrix[0][2]);
    234  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][3]);
    235  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][4]);
    236  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[0][5]);
    237 }
    238 
    239 TEST(ChannelMixingMatrixTest, FiveOneBackToStereo) {
    240  // Front L, Front R, Front C, LFE, Back L, Back R
    241  ChannelLayout input_layout = CHANNEL_LAYOUT_5_1_BACK;
    242  ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO;
    243  const int input_channels = ChannelLayoutToChannelCount(input_layout);
    244  const int output_channels = ChannelLayoutToChannelCount(output_layout);
    245  ChannelMixingMatrix matrix_builder(input_layout, input_channels,
    246                                     output_layout, output_channels);
    247  std::vector<std::vector<float>> matrix;
    248  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    249 
    250  // Note: 1/sqrt(2) is shown as 0.707.
    251  // Note: The Channels enumerator is given by {LEFT = 0, RIGHT, CENTER, LFE,
    252  // BACK_LEFT, BACK_RIGHT,...}, hence we can use the enumerator values as
    253  // indexes in the matrix when verifying the scaling factors.
    254  //
    255  //                      Input: 5.1
    256  //                      LEFT   RIGHT  CENTER  LFE    BACK_LEFT  BACK_RIGHT
    257  // Output: stereo LEFT  1      0      0.707   0.707  0.707      0
    258  //                RIGHT 0      1      0.707   0.707  0          0.707
    259  //
    260  EXPECT_FALSE(remapping);
    261  EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    262  EXPECT_EQ(static_cast<size_t>(input_channels), matrix[LEFT].size());
    263  EXPECT_EQ(static_cast<size_t>(input_channels), matrix[RIGHT].size());
    264  EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
    265  EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
    266  EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
    267  EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
    268  EXPECT_EQ(0.0f, matrix[LEFT][BACK_RIGHT]);
    269  EXPECT_EQ(0.0f, matrix[RIGHT][BACK_LEFT]);
    270  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][CENTER]);
    271  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][LFE]);
    272  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[LEFT][BACK_LEFT]);
    273  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][CENTER]);
    274  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][LFE]);
    275  EXPECT_FLOAT_EQ(ChannelMixer::kHalfPower, matrix[RIGHT][BACK_RIGHT]);
    276 }
    277 
    278 TEST(ChannelMixingMatrixTest, FiveOneToSevenOne) {
    279  // Front L, Front R, Front C, LFE, Side L, Side R
    280  ChannelLayout input_layout = CHANNEL_LAYOUT_5_1;
    281  // Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R
    282  ChannelLayout output_layout = CHANNEL_LAYOUT_7_1;
    283  const int input_channels = ChannelLayoutToChannelCount(input_layout);
    284  const int output_channels = ChannelLayoutToChannelCount(output_layout);
    285  ChannelMixingMatrix matrix_builder(input_layout, input_channels,
    286                                     output_layout, output_channels);
    287  std::vector<std::vector<float>> matrix;
    288  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    289 
    290  //                        Input: 5.1
    291  //                        LEFT   RIGHT  CENTER  LFE    SIDE_LEFT  SIDE_RIGHT
    292  // Output: 7.1 LEFT       1      0      0       0      0          0
    293  //             RIGHT      0      1      0       0      0          0
    294  //             CENTER     0      0      1       0      0          0
    295  //             LFE        0      0      0       1      0          0
    296  //             SIDE_LEFT  0      0      0       0      1          0
    297  //             SIDE_RIGHT 0      0      0       0      0          1
    298  //             BACK_LEFT  0      0      0       0      0          0
    299  //             BACK_RIGHT 0      0      0       0      0          0
    300  //
    301  EXPECT_TRUE(remapping);
    302  EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    303  for (int i = 0; i < output_channels; i++) {
    304    EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
    305    for (int j = 0; j < input_channels; j++) {
    306      if (i == j) {
    307        EXPECT_EQ(1.0f, matrix[i][j]);
    308      } else {
    309        EXPECT_EQ(0.0f, matrix[i][j]);
    310      }
    311    }
    312  }
    313 }
    314 
    315 TEST(ChannelMixingMatrixTest, StereoToFiveOne) {
    316  ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO;
    317  ChannelLayout output_layout = CHANNEL_LAYOUT_5_1;
    318  const int input_channels = ChannelLayoutToChannelCount(input_layout);
    319  const int output_channels = ChannelLayoutToChannelCount(output_layout);
    320  ChannelMixingMatrix matrix_builder(input_layout, input_channels,
    321                                     output_layout, output_channels);
    322  std::vector<std::vector<float>> matrix;
    323  bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    324 
    325  //                         Input: Stereo
    326  //                         LEFT   RIGHT
    327  // Output: 5.1 LEFT        1      0
    328  //             RIGHT       0      1
    329  //             CENTER      0      0
    330  //             LFE         0      0
    331  //             SIDE_LEFT   0      0
    332  //             SIDE_RIGHT  0      0
    333  //
    334  EXPECT_TRUE(remapping);
    335  EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    336  for (int n = 0; n < output_channels; n++) {
    337    EXPECT_EQ(static_cast<size_t>(input_channels), matrix[n].size());
    338    if (n == LEFT) {
    339      EXPECT_EQ(1.0f, matrix[LEFT][LEFT]);
    340      EXPECT_EQ(0.0f, matrix[LEFT][RIGHT]);
    341    } else if (n == RIGHT) {
    342      EXPECT_EQ(0.0f, matrix[RIGHT][LEFT]);
    343      EXPECT_EQ(1.0f, matrix[RIGHT][RIGHT]);
    344    } else {
    345      EXPECT_EQ(0.0f, matrix[n][LEFT]);
    346      EXPECT_EQ(0.0f, matrix[n][RIGHT]);
    347    }
    348  }
    349 }
    350 
    351 TEST(ChannelMixingMatrixTest, DiscreteToDiscrete) {
    352  const struct {
    353    int input_channels;
    354    int output_channels;
    355  } test_case[] = {
    356      {.input_channels = 2, .output_channels = 2},
    357      {.input_channels = 2, .output_channels = 5},
    358      {.input_channels = 5, .output_channels = 2},
    359  };
    360 
    361  for (auto [input_channels, output_channels] : test_case) {
    362    ChannelMixingMatrix matrix_builder(CHANNEL_LAYOUT_DISCRETE, input_channels,
    363                                       CHANNEL_LAYOUT_DISCRETE,
    364                                       output_channels);
    365    std::vector<std::vector<float>> matrix;
    366    bool remapping = matrix_builder.CreateTransformationMatrix(&matrix);
    367    EXPECT_TRUE(remapping);
    368    EXPECT_EQ(static_cast<size_t>(output_channels), matrix.size());
    369    for (int i = 0; i < output_channels; i++) {
    370      EXPECT_EQ(static_cast<size_t>(input_channels), matrix[i].size());
    371      for (int j = 0; j < input_channels; j++) {
    372        if (i == j) {
    373          EXPECT_EQ(1.0f, matrix[i][j]);
    374        } else {
    375          EXPECT_EQ(0.0f, matrix[i][j]);
    376        }
    377      }
    378    }
    379  }
    380 }
    381 
    382 }  // namespace webrtc