tor-browser

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

remix_resample_unittest.cc (10261B)


      1 /*
      2 *  Copyright (c) 2012 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/remix_resample.h"
     12 
     13 #include <cmath>
     14 #include <cstddef>
     15 #include <cstdint>
     16 #include <cstdio>
     17 
     18 #include "api/audio/audio_frame.h"
     19 #include "common_audio/resampler/include/push_resampler.h"
     20 #include "test/gtest.h"
     21 
     22 namespace webrtc {
     23 namespace voe {
     24 namespace {
     25 
     26 int GetFrameSize(int sample_rate_hz) {
     27  return sample_rate_hz / 100;
     28 }
     29 
     30 class UtilityTest : public ::testing::Test {
     31 protected:
     32  UtilityTest() {
     33    src_frame_.sample_rate_hz_ = 16000;
     34    src_frame_.samples_per_channel_ = src_frame_.sample_rate_hz_ / 100;
     35    src_frame_.num_channels_ = 1;
     36    dst_frame_.CopyFrom(src_frame_);
     37    golden_frame_.CopyFrom(src_frame_);
     38  }
     39 
     40  void RunResampleTest(int src_channels,
     41                       int src_sample_rate_hz,
     42                       int dst_channels,
     43                       int dst_sample_rate_hz);
     44 
     45  PushResampler<int16_t> resampler_;
     46  AudioFrame src_frame_;
     47  AudioFrame dst_frame_;
     48  AudioFrame golden_frame_;
     49 };
     50 
     51 // Sets the signal value to increase by `data` with every sample. Floats are
     52 // used so non-integer values result in rounding error, but not an accumulating
     53 // error.
     54 void SetMonoFrame(float data, int sample_rate_hz, AudioFrame* frame) {
     55  frame->Mute();
     56  frame->num_channels_ = 1;
     57  frame->sample_rate_hz_ = sample_rate_hz;
     58  frame->samples_per_channel_ = GetFrameSize(sample_rate_hz);
     59  int16_t* frame_data = frame->mutable_data();
     60  for (size_t i = 0; i < frame->samples_per_channel_; i++) {
     61    frame_data[i] = static_cast<int16_t>(data * i);
     62  }
     63 }
     64 
     65 // Keep the existing sample rate.
     66 void SetMonoFrame(float data, AudioFrame* frame) {
     67  SetMonoFrame(data, frame->sample_rate_hz_, frame);
     68 }
     69 
     70 // Sets the signal value to increase by `left` and `right` with every sample in
     71 // each channel respectively.
     72 void SetStereoFrame(float left,
     73                    float right,
     74                    int sample_rate_hz,
     75                    AudioFrame* frame) {
     76  frame->Mute();
     77  frame->num_channels_ = 2;
     78  frame->sample_rate_hz_ = sample_rate_hz;
     79  frame->samples_per_channel_ = GetFrameSize(sample_rate_hz);
     80  int16_t* frame_data = frame->mutable_data();
     81  for (size_t i = 0; i < frame->samples_per_channel_; i++) {
     82    frame_data[i * 2] = static_cast<int16_t>(left * i);
     83    frame_data[i * 2 + 1] = static_cast<int16_t>(right * i);
     84  }
     85 }
     86 
     87 // Keep the existing sample rate.
     88 void SetStereoFrame(float left, float right, AudioFrame* frame) {
     89  SetStereoFrame(left, right, frame->sample_rate_hz_, frame);
     90 }
     91 
     92 // Sets the signal value to increase by `ch1`, `ch2`, `ch3`, `ch4` with every
     93 // sample in each channel respectively.
     94 void SetQuadFrame(float ch1,
     95                  float ch2,
     96                  float ch3,
     97                  float ch4,
     98                  int sample_rate_hz,
     99                  AudioFrame* frame) {
    100  frame->Mute();
    101  frame->num_channels_ = 4;
    102  frame->sample_rate_hz_ = sample_rate_hz;
    103  frame->samples_per_channel_ = GetFrameSize(sample_rate_hz);
    104  int16_t* frame_data = frame->mutable_data();
    105  for (size_t i = 0; i < frame->samples_per_channel_; i++) {
    106    frame_data[i * 4] = static_cast<int16_t>(ch1 * i);
    107    frame_data[i * 4 + 1] = static_cast<int16_t>(ch2 * i);
    108    frame_data[i * 4 + 2] = static_cast<int16_t>(ch3 * i);
    109    frame_data[i * 4 + 3] = static_cast<int16_t>(ch4 * i);
    110  }
    111 }
    112 
    113 void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) {
    114  EXPECT_EQ(ref_frame.num_channels_, test_frame.num_channels_);
    115  EXPECT_EQ(ref_frame.samples_per_channel_, test_frame.samples_per_channel_);
    116  EXPECT_EQ(ref_frame.sample_rate_hz_, test_frame.sample_rate_hz_);
    117 }
    118 
    119 // Computes the best SNR based on the error between `ref_frame` and
    120 // `test_frame`. It allows for up to a `max_delay` in samples between the
    121 // signals to compensate for the resampling delay.
    122 float ComputeSNR(const AudioFrame& ref_frame,
    123                 const AudioFrame& test_frame,
    124                 size_t max_delay) {
    125  VerifyParams(ref_frame, test_frame);
    126  float best_snr = 0;
    127  size_t best_delay = 0;
    128  for (size_t delay = 0; delay <= max_delay; delay++) {
    129    float mse = 0;
    130    float variance = 0;
    131    const int16_t* ref_frame_data = ref_frame.data();
    132    const int16_t* test_frame_data = test_frame.data();
    133    for (size_t i = 0;
    134         i < ref_frame.samples_per_channel_ * ref_frame.num_channels_ - delay;
    135         i++) {
    136      int error = ref_frame_data[i] - test_frame_data[i + delay];
    137      mse += error * error;
    138      variance += ref_frame_data[i] * ref_frame_data[i];
    139    }
    140    float snr = 100;  // We assign 100 dB to the zero-error case.
    141    if (mse > 0)
    142      snr = 10 * std::log10(variance / mse);
    143    if (snr > best_snr) {
    144      best_snr = snr;
    145      best_delay = delay;
    146    }
    147  }
    148  printf("SNR=%.1f dB at delay=%zu\n", best_snr, best_delay);
    149  return best_snr;
    150 }
    151 
    152 void VerifyFramesAreEqual(const AudioFrame& ref_frame,
    153                          const AudioFrame& test_frame) {
    154  VerifyParams(ref_frame, test_frame);
    155  const int16_t* ref_frame_data = ref_frame.data();
    156  const int16_t* test_frame_data = test_frame.data();
    157  for (size_t i = 0;
    158       i < ref_frame.samples_per_channel_ * ref_frame.num_channels_; i++) {
    159    EXPECT_EQ(ref_frame_data[i], test_frame_data[i]);
    160  }
    161 }
    162 
    163 void UtilityTest::RunResampleTest(int src_channels,
    164                                  int src_sample_rate_hz,
    165                                  int dst_channels,
    166                                  int dst_sample_rate_hz) {
    167  PushResampler<int16_t> resampler;  // Create a new one with every test.
    168  const int16_t kSrcCh1 = 30;  // Shouldn't overflow for any used sample rate.
    169  const int16_t kSrcCh2 = 15;
    170  const int16_t kSrcCh3 = 22;
    171  const int16_t kSrcCh4 = 8;
    172  const float resampling_factor =
    173      (1.0 * src_sample_rate_hz) / dst_sample_rate_hz;
    174  const float dst_ch1 = resampling_factor * kSrcCh1;
    175  const float dst_ch2 = resampling_factor * kSrcCh2;
    176  const float dst_ch3 = resampling_factor * kSrcCh3;
    177  const float dst_ch4 = resampling_factor * kSrcCh4;
    178  const float dst_stereo_to_mono = (dst_ch1 + dst_ch2) / 2;
    179  const float dst_quad_to_mono = (dst_ch1 + dst_ch2 + dst_ch3 + dst_ch4) / 4;
    180  const float dst_quad_to_stereo_ch1 = (dst_ch1 + dst_ch2) / 2;
    181  const float dst_quad_to_stereo_ch2 = (dst_ch3 + dst_ch4) / 2;
    182  if (src_channels == 1)
    183    SetMonoFrame(kSrcCh1, src_sample_rate_hz, &src_frame_);
    184  else if (src_channels == 2)
    185    SetStereoFrame(kSrcCh1, kSrcCh2, src_sample_rate_hz, &src_frame_);
    186  else
    187    SetQuadFrame(kSrcCh1, kSrcCh2, kSrcCh3, kSrcCh4, src_sample_rate_hz,
    188                 &src_frame_);
    189 
    190  if (dst_channels == 1) {
    191    SetMonoFrame(0, dst_sample_rate_hz, &dst_frame_);
    192    if (src_channels == 1)
    193      SetMonoFrame(dst_ch1, dst_sample_rate_hz, &golden_frame_);
    194    else if (src_channels == 2)
    195      SetMonoFrame(dst_stereo_to_mono, dst_sample_rate_hz, &golden_frame_);
    196    else
    197      SetMonoFrame(dst_quad_to_mono, dst_sample_rate_hz, &golden_frame_);
    198  } else {
    199    SetStereoFrame(0, 0, dst_sample_rate_hz, &dst_frame_);
    200    if (src_channels == 1)
    201      SetStereoFrame(dst_ch1, dst_ch1, dst_sample_rate_hz, &golden_frame_);
    202    else if (src_channels == 2)
    203      SetStereoFrame(dst_ch1, dst_ch2, dst_sample_rate_hz, &golden_frame_);
    204    else
    205      SetStereoFrame(dst_quad_to_stereo_ch1, dst_quad_to_stereo_ch2,
    206                     dst_sample_rate_hz, &golden_frame_);
    207  }
    208 
    209  // The sinc resampler has a known delay, which we compute here. Multiplying by
    210  // two gives us a crude maximum for any resampling, as the old resampler
    211  // typically (but not always) has lower delay.
    212  static const size_t kInputKernelDelaySamples = 16;
    213  const size_t max_delay = static_cast<size_t>(
    214      static_cast<double>(dst_sample_rate_hz) / src_sample_rate_hz *
    215      kInputKernelDelaySamples * dst_channels * 2);
    216  printf("(%d, %d Hz) -> (%d, %d Hz) ",  // SNR reported on the same line later.
    217         src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
    218  RemixAndResample(src_frame_, &resampler, &dst_frame_);
    219 
    220  if (src_sample_rate_hz == 96000 && dst_sample_rate_hz <= 11025) {
    221    // The sinc resampler gives poor SNR at this extreme conversion, but we
    222    // expect to see this rarely in practice.
    223    EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 14.0f);
    224  } else {
    225    EXPECT_GT(ComputeSNR(golden_frame_, dst_frame_, max_delay), 46.0f);
    226  }
    227 }
    228 
    229 TEST_F(UtilityTest, RemixAndResampleCopyFrameSucceeds) {
    230  // Stereo -> stereo.
    231  SetStereoFrame(10, 10, &src_frame_);
    232  SetStereoFrame(0, 0, &dst_frame_);
    233  RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    234  VerifyFramesAreEqual(src_frame_, dst_frame_);
    235 
    236  // Mono -> mono.
    237  SetMonoFrame(20, &src_frame_);
    238  SetMonoFrame(0, &dst_frame_);
    239  RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    240  VerifyFramesAreEqual(src_frame_, dst_frame_);
    241 }
    242 
    243 TEST_F(UtilityTest, RemixAndResampleMixingOnlySucceeds) {
    244  // Stereo -> mono.
    245  SetStereoFrame(0, 0, &dst_frame_);
    246  SetMonoFrame(10, &src_frame_);
    247  SetStereoFrame(10, 10, &golden_frame_);
    248  RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    249  VerifyFramesAreEqual(dst_frame_, golden_frame_);
    250 
    251  // Mono -> stereo.
    252  SetMonoFrame(0, &dst_frame_);
    253  SetStereoFrame(10, 20, &src_frame_);
    254  SetMonoFrame(15, &golden_frame_);
    255  RemixAndResample(src_frame_, &resampler_, &dst_frame_);
    256  VerifyFramesAreEqual(golden_frame_, dst_frame_);
    257 }
    258 
    259 TEST_F(UtilityTest, RemixAndResampleSucceeds) {
    260  const int kSampleRates[] = {8000,  11025, 16000, 22050,
    261                              32000, 44100, 48000, 96000};
    262  const int kSrcChannels[] = {1, 2, 4};
    263  const int kDstChannels[] = {1, 2};
    264 
    265  for (int src_rate : kSampleRates) {
    266    for (int dst_rate : kSampleRates) {
    267      for (size_t src_channels : kSrcChannels) {
    268        for (size_t dst_channels : kDstChannels) {
    269          RunResampleTest(src_channels, src_rate, dst_channels, dst_rate);
    270        }
    271      }
    272    }
    273  }
    274 }
    275 
    276 }  // namespace
    277 }  // namespace voe
    278 }  // namespace webrtc