15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MSVC++ requires this to be set before any other includes to get M_PI.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _USE_MATH_DEFINES
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/sinc_resampler.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using testing::_;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kSampleRateRatio = 192000.0 / 44100.0;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class to ensure ChunkedResample() functions properly.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockSource {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
28b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  MOCK_METHOD2(ProvideInput, void(int frames, float* destination));
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ACTION(ClearBuffer) {
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  memset(arg1, 0, arg0 * sizeof(float));
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ACTION(FillBuffer) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Value chosen arbitrarily such that SincResampler resamples it to something
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // easily representable on all platforms; e.g., using kSampleRateRatio this
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // becomes 1.81219.
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  memset(arg1, 64, arg0 * sizeof(float));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test requesting multiples of ChunkSize() frames results in the proper number
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of callbacks.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SincResamplerTest, ChunkedResample) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSource mock_source;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Choose a high ratio of input to output samples which will result in quick
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exhaustion of SincResampler's internal buffers.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SincResampler resampler(
50b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      kSampleRateRatio, SincResampler::kDefaultRequestSize,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source)));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kChunks = 2;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int max_chunk_size = resampler.ChunkSize() * kChunks;
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<float[]> resampled_destination(new float[max_chunk_size]);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify requesting ChunkSize() frames causes a single callback.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(mock_source, ProvideInput(_, _))
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .Times(1).WillOnce(ClearBuffer());
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  resampler.Resample(resampler.ChunkSize(), resampled_destination.get());
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testing::Mock::VerifyAndClear(&mock_source);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(mock_source, ProvideInput(_, _))
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .Times(kChunks).WillRepeatedly(ClearBuffer());
66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  resampler.Resample(max_chunk_size, resampled_destination.get());
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test flush resets the internal state properly.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SincResamplerTest, Flush) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSource mock_source;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SincResampler resampler(
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      kSampleRateRatio, SincResampler::kDefaultRequestSize,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source)));
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<float[]> resampled_destination(new float[resampler.ChunkSize()]);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the resampler with junk data.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(mock_source, ProvideInput(_, _))
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .Times(1).WillOnce(FillBuffer());
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NE(resampled_destination[0], 0);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush and request more data, which should all be zeros now.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resampler.Flush();
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testing::Mock::VerifyAndClear(&mock_source);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_CALL(mock_source, ProvideInput(_, _))
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      .Times(1).WillOnce(ClearBuffer());
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < resampler.ChunkSize() / 2; ++i)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ASSERT_FLOAT_EQ(resampled_destination[i], 0);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Test flush resets the internal state properly.
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)TEST(SincResamplerTest, DISABLED_SetRatioBench) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  MockSource mock_source;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SincResampler resampler(
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      kSampleRateRatio, SincResampler::kDefaultRequestSize,
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source)));
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::TimeTicks start = base::TimeTicks::HighResNow();
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (int i = 1; i < 10000; ++i)
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    resampler.SetRatio(1.0 / i);
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  double total_time_c_ms =
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (base::TimeTicks::HighResNow() - start).InMillisecondsF();
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  printf("SetRatio() took %.2fms.\n", total_time_c_ms);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Define platform independent function name for Convolve* tests.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(ARCH_CPU_X86_FAMILY)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CONVOLVE_FUNC Convolve_SSE
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CONVOLVE_FUNC Convolve_NEON
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Ensure various optimized Convolve() methods return the same value.  Only run
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this test if other optimized methods exist, otherwise the default Convolve()
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// will be tested by the parameterized SincResampler tests below.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(CONVOLVE_FUNC)
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)static const double kKernelInterpolationFactor = 0.5;
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(SincResamplerTest, Convolve) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize a dummy resampler.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MockSource mock_source;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SincResampler resampler(
126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      kSampleRateRatio, SincResampler::kDefaultRequestSize,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source)));
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The optimized Convolve methods are slightly more precise than Convolve_C(),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so comparison must be done using an epsilon.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const double kEpsilon = 0.00000005;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use a kernel from SincResampler as input and kernel data, this has the
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // benefit of already being properly sized and aligned for Convolve_SSE().
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double result = resampler.Convolve_C(
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), resampler.kernel_storage_.get(),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), kKernelInterpolationFactor);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double result2 = resampler.CONVOLVE_FUNC(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), resampler.kernel_storage_.get(),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), kKernelInterpolationFactor);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_NEAR(result2, result, kEpsilon);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Convolve() w/ unaligned input pointer.
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = resampler.Convolve_C(
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(),
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), kKernelInterpolationFactor);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result2 = resampler.CONVOLVE_FUNC(
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      resampler.kernel_storage_.get(), kKernelInterpolationFactor);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_NEAR(result2, result, kEpsilon);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fake audio source for testing the resampler.  Generates a sinusoidal linear
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resampler for the specific sample rate conversion being used.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SinusoidalLinearChirpSource {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  SinusoidalLinearChirpSource(int sample_rate,
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                              int samples,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              double max_frequency)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : sample_rate_(sample_rate),
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        total_samples_(samples),
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        max_frequency_(max_frequency),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_index_(0) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Chirp rate.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double duration = static_cast<double>(total_samples_) / sample_rate_;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    k_ = (max_frequency_ - kMinFrequency) / duration;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SinusoidalLinearChirpSource() {}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  void ProvideInput(int frames, float* destination) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < frames; ++i, ++current_index_) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Filter out frequencies higher than Nyquist.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (Frequency(current_index_) > 0.5 * sample_rate_) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        destination[i] = 0;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Calculate time in seconds.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        double t = static_cast<double>(current_index_) / sample_rate_;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Sinusoidal linear chirp.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t));
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double Frequency(int position) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kMinFrequency + position * (max_frequency_ - kMinFrequency)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        / total_samples_;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kMinFrequency = 5
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double sample_rate_;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int total_samples_;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double max_frequency_;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double k_;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_index_;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef std::tr1::tuple<int, int, double, double> SincResamplerTestData;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SincResamplerTest
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public testing::TestWithParam<SincResamplerTestData> {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SincResamplerTest()
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : input_rate_(std::tr1::get<0>(GetParam())),
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        output_rate_(std::tr1::get<1>(GetParam())),
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rms_error_(std::tr1::get<2>(GetParam())),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        low_freq_error_(std::tr1::get<3>(GetParam())) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SincResamplerTest() {}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_rate_;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int output_rate_;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double rms_error_;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double low_freq_error_;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Tests resampling using a given input and output sample rate.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_P(SincResamplerTest, Resample) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make comparisons using one second of data.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const double kTestDurationSecs = 1;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int input_samples = kTestDurationSecs * input_rate_;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int output_samples = kTestDurationSecs * output_rate_;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nyquist frequency for the input sampling rate.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double input_nyquist_freq = 0.5 * input_rate_;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Source for data to be resampled.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SinusoidalLinearChirpSource resampler_source(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      input_rate_, input_samples, input_nyquist_freq);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const double io_ratio = input_rate_ / static_cast<double>(output_rate_);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SincResampler resampler(
243b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      io_ratio, SincResampler::kDefaultRequestSize,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&SinusoidalLinearChirpSource::ProvideInput,
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(&resampler_source)));
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Force an update to the sample rate ratio to ensure dyanmic sample rate
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // changes are working correctly.
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<float[]> kernel(new float[SincResampler::kKernelStorageSize]);
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  memcpy(kernel.get(), resampler.get_kernel_for_testing(),
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         SincResampler::kKernelStorageSize);
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  resampler.SetRatio(M_PI);
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_NE(0, memcmp(kernel.get(), resampler.get_kernel_for_testing(),
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      SincResampler::kKernelStorageSize));
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  resampler.SetRatio(io_ratio);
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(0, memcmp(kernel.get(), resampler.get_kernel_for_testing(),
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      SincResampler::kKernelStorageSize));
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<float[]> resampled_destination(new float[output_samples]);
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<float[]> pure_destination(new float[output_samples]);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate resampled signal.
265b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  resampler.Resample(output_samples, resampled_destination.get());
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate pure signal.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SinusoidalLinearChirpSource pure_source(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output_rate_, output_samples, input_nyquist_freq);
270b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  pure_source.ProvideInput(output_samples, pure_destination.get());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we refer to as low and high.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const double kLowFrequencyNyquistRange = 0.7;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const double kHighFrequencyNyquistRange = 0.9;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calculate Root-Mean-Square-Error and maximum error for the resampling.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double sum_of_squares = 0;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double low_freq_max_error = 0;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double high_freq_max_error = 0;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int minimum_rate = std::min(input_rate_, output_rate_);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double low_frequency_range = kLowFrequencyNyquistRange * 0.5 * minimum_rate;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double high_frequency_range = kHighFrequencyNyquistRange * 0.5 * minimum_rate;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < output_samples; ++i) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    double error = fabs(resampled_destination[i] - pure_destination[i]);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pure_source.Frequency(i) < low_frequency_range) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error > low_freq_max_error)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        low_freq_max_error = error;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (pure_source.Frequency(i) < high_frequency_range) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (error > high_freq_max_error)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        high_freq_max_error = error;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(dalecurtis): Sanity check frequencies > kHighFrequencyNyquistRange.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sum_of_squares += error * error;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double rms_error = sqrt(sum_of_squares / output_samples);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert each error to dbFS.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #define DBFS(x) 20 * log10(x)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rms_error = DBFS(rms_error);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  low_freq_max_error = DBFS(low_freq_max_error);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  high_freq_max_error = DBFS(high_freq_max_error);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_LE(rms_error, rms_error_);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_LE(low_freq_max_error, low_freq_error_);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All conversions currently have a high frequency error around -6 dbFS.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const double kHighFrequencyMaxError = -6.02;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_LE(high_freq_max_error, kHighFrequencyMaxError);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Almost all conversions have an RMS error of around -14 dbFS.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const double kResamplingRMSError = -14.58;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Thresholds chosen arbitrarily based on what each resampling reported during
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// testing.  All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)INSTANTIATE_TEST_CASE_P(
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SincResamplerTest, SincResamplerTest, testing::Values(
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // To 44.1kHz
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(8000, 44100, kResamplingRMSError, -62.73),
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(11025, 44100, kResamplingRMSError, -72.19),
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(16000, 44100, kResamplingRMSError, -62.54),
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(22050, 44100, kResamplingRMSError, -73.53),
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(32000, 44100, kResamplingRMSError, -63.32),
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(44100, 44100, kResamplingRMSError, -73.53),
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(48000, 44100, -15.01, -64.04),
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(96000, 44100, -18.49, -25.51),
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(192000, 44100, -20.50, -13.31),
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // To 48kHz
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(8000, 48000, kResamplingRMSError, -63.43),
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(11025, 48000, kResamplingRMSError, -62.61),
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(16000, 48000, kResamplingRMSError, -63.96),
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(22050, 48000, kResamplingRMSError, -62.42),
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(32000, 48000, kResamplingRMSError, -64.04),
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(44100, 48000, kResamplingRMSError, -62.63),
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(48000, 48000, kResamplingRMSError, -73.52),
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(96000, 48000, -18.40, -28.44),
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(192000, 48000, -20.43, -14.11),
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // To 96kHz
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(8000, 96000, kResamplingRMSError, -63.19),
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(11025, 96000, kResamplingRMSError, -62.61),
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(16000, 96000, kResamplingRMSError, -63.39),
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(22050, 96000, kResamplingRMSError, -62.42),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(32000, 96000, kResamplingRMSError, -63.95),
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(44100, 96000, kResamplingRMSError, -62.63),
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(48000, 96000, kResamplingRMSError, -73.52),
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(96000, 96000, kResamplingRMSError, -73.52),
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(192000, 96000, kResamplingRMSError, -28.41),
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // To 192kHz
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(8000, 192000, kResamplingRMSError, -63.10),
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(11025, 192000, kResamplingRMSError, -62.61),
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(16000, 192000, kResamplingRMSError, -63.14),
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(22050, 192000, kResamplingRMSError, -62.42),
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(32000, 192000, kResamplingRMSError, -63.38),
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(44100, 192000, kResamplingRMSError, -62.63),
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(48000, 192000, kResamplingRMSError, -73.44),
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(96000, 192000, kResamplingRMSError, -73.52),
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::tr1::make_tuple(192000, 192000, kResamplingRMSError, -73.52)));
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace media
367