tor-browser

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

audio_converter_unittest.cc (5729B)


      1 /*
      2 *  Copyright (c) 2014 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 "common_audio/audio_converter.h"
     12 
     13 #include <algorithm>
     14 #include <cmath>
     15 #include <cstddef>
     16 #include <cstdio>
     17 #include <memory>
     18 #include <vector>
     19 
     20 #include "common_audio/channel_buffer.h"
     21 #include "common_audio/resampler/push_sinc_resampler.h"
     22 #include "test/gtest.h"
     23 
     24 namespace webrtc {
     25 
     26 typedef std::unique_ptr<ChannelBuffer<float>> ScopedBuffer;
     27 
     28 // Sets the signal value to increase by `data` with every sample.
     29 ScopedBuffer CreateBuffer(const std::vector<float>& data, size_t frames) {
     30  const size_t num_channels = data.size();
     31  ScopedBuffer sb(new ChannelBuffer<float>(frames, num_channels));
     32  for (size_t i = 0; i < num_channels; ++i)
     33    for (size_t j = 0; j < frames; ++j)
     34      sb->channels()[i][j] = data[i] * j;
     35  return sb;
     36 }
     37 
     38 void VerifyParams(const ChannelBuffer<float>& ref,
     39                  const ChannelBuffer<float>& test) {
     40  EXPECT_EQ(ref.num_channels(), test.num_channels());
     41  EXPECT_EQ(ref.num_frames(), test.num_frames());
     42 }
     43 
     44 // Computes the best SNR based on the error between `ref_frame` and
     45 // `test_frame`. It searches around `expected_delay` in samples between the
     46 // signals to compensate for the resampling delay.
     47 float ComputeSNR(const ChannelBuffer<float>& ref,
     48                 const ChannelBuffer<float>& test,
     49                 size_t expected_delay) {
     50  VerifyParams(ref, test);
     51  float best_snr = 0;
     52  size_t best_delay = 0;
     53 
     54  // Search within one sample of the expected delay.
     55  for (size_t delay = std::max(expected_delay, static_cast<size_t>(1)) - 1;
     56       delay <= std::min(expected_delay + 1, ref.num_frames()); ++delay) {
     57    float mse = 0;
     58    float variance = 0;
     59    float mean = 0;
     60    for (size_t i = 0; i < ref.num_channels(); ++i) {
     61      for (size_t j = 0; j < ref.num_frames() - delay; ++j) {
     62        float error = ref.channels()[i][j] - test.channels()[i][j + delay];
     63        mse += error * error;
     64        variance += ref.channels()[i][j] * ref.channels()[i][j];
     65        mean += ref.channels()[i][j];
     66      }
     67    }
     68 
     69    const size_t length = ref.num_channels() * (ref.num_frames() - delay);
     70    mse /= length;
     71    variance /= length;
     72    mean /= length;
     73    variance -= mean * mean;
     74    float snr = 100;  // We assign 100 dB to the zero-error case.
     75    if (mse > 0)
     76      snr = 10 * std::log10(variance / mse);
     77    if (snr > best_snr) {
     78      best_snr = snr;
     79      best_delay = delay;
     80    }
     81  }
     82  printf("SNR=%.1f dB at delay=%zu\n", best_snr, best_delay);
     83  return best_snr;
     84 }
     85 
     86 // Sets the source to a linearly increasing signal for which we can easily
     87 // generate a reference. Runs the AudioConverter and ensures the output has
     88 // sufficiently high SNR relative to the reference.
     89 void RunAudioConverterTest(size_t src_channels,
     90                           int src_sample_rate_hz,
     91                           size_t dst_channels,
     92                           int dst_sample_rate_hz) {
     93  const float kSrcLeft = 0.0002f;
     94  const float kSrcRight = 0.0001f;
     95  const float resampling_factor =
     96      (1.f * src_sample_rate_hz) / dst_sample_rate_hz;
     97  const float dst_left = resampling_factor * kSrcLeft;
     98  const float dst_right = resampling_factor * kSrcRight;
     99  const float dst_mono = (dst_left + dst_right) / 2;
    100  const size_t src_frames = static_cast<size_t>(src_sample_rate_hz / 100);
    101  const size_t dst_frames = static_cast<size_t>(dst_sample_rate_hz / 100);
    102 
    103  std::vector<float> src_data(1, kSrcLeft);
    104  if (src_channels == 2)
    105    src_data.push_back(kSrcRight);
    106  ScopedBuffer src_buffer = CreateBuffer(src_data, src_frames);
    107 
    108  std::vector<float> dst_data(1, 0);
    109  std::vector<float> ref_data;
    110  if (dst_channels == 1) {
    111    if (src_channels == 1)
    112      ref_data.push_back(dst_left);
    113    else
    114      ref_data.push_back(dst_mono);
    115  } else {
    116    dst_data.push_back(0);
    117    ref_data.push_back(dst_left);
    118    if (src_channels == 1)
    119      ref_data.push_back(dst_left);
    120    else
    121      ref_data.push_back(dst_right);
    122  }
    123  ScopedBuffer dst_buffer = CreateBuffer(dst_data, dst_frames);
    124  ScopedBuffer ref_buffer = CreateBuffer(ref_data, dst_frames);
    125 
    126  // The sinc resampler has a known delay, which we compute here.
    127  const size_t delay_frames =
    128      src_sample_rate_hz == dst_sample_rate_hz
    129          ? 0
    130          : static_cast<size_t>(
    131                PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) *
    132                dst_sample_rate_hz);
    133  // SNR reported on the same line later.
    134  printf("(%zu, %d Hz) -> (%zu, %d Hz) ", src_channels, src_sample_rate_hz,
    135         dst_channels, dst_sample_rate_hz);
    136 
    137  std::unique_ptr<AudioConverter> converter = AudioConverter::Create(
    138      src_channels, src_frames, dst_channels, dst_frames);
    139  converter->Convert(src_buffer->channels(), src_buffer->size(),
    140                     dst_buffer->channels(), dst_buffer->size());
    141 
    142  EXPECT_LT(43.f,
    143            ComputeSNR(*ref_buffer.get(), *dst_buffer.get(), delay_frames));
    144 }
    145 
    146 TEST(AudioConverterTest, ConversionsPassSNRThreshold) {
    147  const int kSampleRates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
    148  const int kChannels[] = {1, 2};
    149  for (int src_rate : kSampleRates) {
    150    for (int dst_rate : kSampleRates) {
    151      for (size_t src_channels : kChannels) {
    152        for (size_t dst_channels : kChannels) {
    153          RunAudioConverterTest(src_channels, src_rate, dst_channels, dst_rate);
    154        }
    155      }
    156    }
    157  }
    158 }
    159 
    160 }  // namespace webrtc