Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 // MSVC++ requires this to be set before any other includes to get M_PI. | |
| 5 #define _USE_MATH_DEFINES | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/stringprintf.h" | |
| 12 #include "media/base/sinc_resampler.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 namespace media { | |
| 16 | |
| 17 // Chosen arbitrarily on what each resampler reported during testing. | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
s/on/based on/
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 18 static const double kMaxRMSError = 0.0002; | |
|
Chris Rogers
2012/07/02 20:38:14
I'm not sure if the RMS error will be useful, but
DaleCurtis
2012/07/03 00:36:34
Happy to drop it, but I figured there would be cas
| |
| 19 static const double kMaxError = 0.00022; | |
|
Chris Rogers
2012/07/02 20:38:14
I'd represent this in decibels (actually dbFS) - s
| |
| 20 | |
| 21 // Generate a swept sine wave with the given hertz over [0, kCycles * 2 * PI]. | |
| 22 class SweptSineSourceProvider : public SincResampler::AudioSourceProvider { | |
| 23 public: | |
| 24 // Maximum sine wave cycles. | |
| 25 static const int kCycles = 6; | |
|
Chris Rogers
2012/07/02 20:38:14
As we discussed in chat, I think we should define
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 26 | |
| 27 // Hz/sec value for the swept sine wave. | |
| 28 // TODO(dalecurtis): Should we use a more complex pattern here? | |
| 29 static const int kHertzPerSecond = 1; | |
|
Chris Rogers
2012/07/02 20:38:14
I don't think we'll need this constant.
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 30 | |
| 31 explicit SweptSineSourceProvider(int max) { | |
|
Chris Rogers
2012/07/02 20:38:14
"max"? how about "sample_rate"
Then I'd simply g
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 32 ResetTimeState(max); | |
| 33 } | |
| 34 | |
| 35 virtual ~SweptSineSourceProvider() {} | |
| 36 | |
| 37 virtual void ProvideInput(float* destination, int number_of_frames) OVERRIDE { | |
| 38 for (int i = 0; i < number_of_frames; ++i) { | |
| 39 destination[i] = sin(kHertzPerSecond * time_state_ * time_state_); | |
| 40 time_state_ += time_increment_; | |
| 41 } | |
| 42 } | |
| 43 | |
| 44 void ResetTimeState(int max) { | |
| 45 time_state_ = 0.0; | |
| 46 time_increment_ = kCycles * 2 * M_PI / max; | |
| 47 } | |
| 48 | |
| 49 protected: | |
| 50 double hertz_; | |
| 51 double time_increment_; | |
| 52 double time_state_; | |
| 53 | |
| 54 DISALLOW_COPY_AND_ASSIGN(SweptSineSourceProvider); | |
| 55 }; | |
| 56 | |
| 57 // Used for tests which just need to run without crashing or tooling errors, but | |
| 58 // which may have undefined behavior for hashing, etc. | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
wat?
DaleCurtis
2012/07/01 23:31:30
Copy paste fail! (from ffmpeg_regression_tests)
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 59 struct SincResamplerTestData { | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
Isn't this kind of overkill for a std::pair<int, i
DaleCurtis
2012/07/01 23:31:30
Good point, I completely forgot about pair.
DaleCurtis
2012/07/03 00:36:34
Switched to using tr1::tuple since gtest uses that
| |
| 60 SincResamplerTestData(int input_rate, int output_rate) | |
| 61 : input_rate(input_rate), | |
| 62 output_rate(output_rate) { | |
| 63 } | |
| 64 | |
| 65 std::string DebugString() const { | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
FWIW, since this doesn't touch private data (there
DaleCurtis
2012/07/03 00:36:34
Removed with tuple().
| |
| 66 return base::StringPrintf( | |
| 67 "Resampling test from %dHz to %dHz.", input_rate, output_rate); | |
| 68 } | |
| 69 | |
| 70 const int input_rate; | |
| 71 const int output_rate; | |
| 72 }; | |
| 73 | |
| 74 class SincResamplerTestCase | |
| 75 : public testing::TestWithParam<SincResamplerTestData> { | |
| 76 }; | |
| 77 | |
| 78 // Define ostream << operator so GTest will print nice error messages instead of | |
| 79 // "[...], where GetParam() = 8-byte object <44-AC 00-00 00-77 01-00>" | |
| 80 ::std::ostream& operator<<(::std::ostream& os, | |
| 81 const SincResamplerTestData& data) { | |
| 82 return os << data.DebugString(); | |
| 83 } | |
| 84 | |
| 85 INSTANTIATE_TEST_CASE_P( | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
Traditionally this goes *after* the test case it i
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 86 SincResamplerTest, SincResamplerTestCase, testing::Values( | |
| 87 // To 44.1kHz | |
| 88 SincResamplerTestData(8000, 44100), | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
Replace the explicit lists (which are prone to acc
DaleCurtis
2012/07/01 23:31:30
Neat! I was looking for that.
DaleCurtis
2012/07/03 00:36:34
Don't think we'll be able to use this since after
| |
| 89 SincResamplerTestData(11025, 44100), | |
| 90 SincResamplerTestData(16000, 44100), | |
| 91 SincResamplerTestData(22050, 44100), | |
| 92 SincResamplerTestData(32000, 44100), | |
| 93 SincResamplerTestData(48000, 44100), | |
| 94 SincResamplerTestData(96000, 44100), | |
| 95 SincResamplerTestData(192000, 44100), | |
| 96 | |
| 97 // To 48kHz | |
| 98 SincResamplerTestData(8000, 48000), | |
| 99 SincResamplerTestData(11025, 48000), | |
| 100 SincResamplerTestData(16000, 48000), | |
| 101 SincResamplerTestData(22050, 48000), | |
| 102 SincResamplerTestData(32000, 48000), | |
| 103 SincResamplerTestData(44100, 48000), | |
| 104 SincResamplerTestData(96000, 48000), | |
| 105 SincResamplerTestData(192000, 48000), | |
| 106 | |
| 107 // To 96kHz | |
| 108 SincResamplerTestData(8000, 96000), | |
| 109 SincResamplerTestData(11025, 96000), | |
| 110 SincResamplerTestData(16000, 96000), | |
| 111 SincResamplerTestData(22050, 96000), | |
| 112 SincResamplerTestData(32000, 96000), | |
| 113 SincResamplerTestData(44100, 96000), | |
| 114 SincResamplerTestData(48000, 96000), | |
| 115 SincResamplerTestData(192000, 96000), | |
| 116 | |
| 117 // To 192kHz | |
| 118 SincResamplerTestData(8000, 192000), | |
| 119 SincResamplerTestData(11025, 192000), | |
| 120 SincResamplerTestData(16000, 192000), | |
| 121 SincResamplerTestData(22050, 192000), | |
| 122 SincResamplerTestData(32000, 192000), | |
| 123 SincResamplerTestData(44100, 192000), | |
| 124 SincResamplerTestData(48000, 192000), | |
| 125 SincResamplerTestData(96000, 192000))); | |
| 126 | |
| 127 // Test callback() works as expected. | |
| 128 TEST_P(SincResamplerTestCase, Resample) { | |
| 129 int input_rate = GetParam().input_rate; | |
| 130 int output_rate = GetParam().output_rate; | |
| 131 | |
| 132 scoped_ptr<SweptSineSourceProvider> provider( | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
hopefully you won't need this post-migration-to-CB
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 133 new SweptSineSourceProvider(input_rate)); | |
| 134 scoped_ptr<SincResampler> resampler(new SincResampler( | |
| 135 provider.get(), static_cast<double>(input_rate) / output_rate)); | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
you could avoid this cast by making the input & ou
DaleCurtis
2012/07/03 00:36:34
Then I need two casts for constructing the arrays.
| |
| 136 | |
| 137 // TODO(dalecurtis): These will need SSE appropriate allocations. | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
Do you mean padding/alignment? why not fix now?
DaleCurtis
2012/07/01 23:31:30
Yes, but it's more than just here that needs to be
| |
| 138 scoped_array<float> resampled_destination(new float[output_rate]); | |
| 139 scoped_array<float> pure_destination(new float[output_rate]); | |
| 140 | |
| 141 // Generate resampled signal. | |
| 142 resampler->Resample(resampled_destination.get(), output_rate); | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
It's confusing that output_rate is used for number
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 143 | |
| 144 // Generate pure signal. | |
| 145 provider->ResetTimeState(output_rate); | |
|
Chris Rogers
2012/07/02 20:38:14
Instead of re-using the existing object and exposi
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 146 provider->ProvideInput(pure_destination.get(), output_rate); | |
| 147 | |
| 148 // Calculate Root-Mean-Square-Error for the resampling. | |
| 149 double sum_of_squares = 0.0; | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
.0 here and below unnecessary
DaleCurtis
2012/07/03 00:36:34
Done.
| |
| 150 double max_error = 0.0; | |
| 151 for (int i = 0; i < output_rate; ++i) { | |
| 152 double error = fabs(resampled_destination[i] - pure_destination[i]); | |
| 153 max_error = std::max(max_error, error); | |
| 154 sum_of_squares += error * error; | |
| 155 } | |
| 156 | |
| 157 double rms_error = sqrt(sum_of_squares / output_rate); | |
| 158 | |
| 159 // TODO(dalecurtis): Should this be different for each (in, out) pair? | |
|
Ami GONE FROM CHROMIUM
2012/06/30 20:29:30
how wide is the spread?
DaleCurtis
2012/07/03 00:36:34
rms error is about 0.17 -> 0.55, max: 0.86 -> 1.86
| |
| 160 EXPECT_LT(rms_error, kMaxRMSError); | |
| 161 EXPECT_LT(max_error, kMaxError); | |
| 162 } | |
| 163 | |
| 164 } // namespace media | |
| OLD | NEW |