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/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/logging.h" | |
12 #include "base/memory/scoped_ptr.h" | |
13 #include "base/stringprintf.h" | |
14 #include "media/base/sinc_resampler.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace media { | |
18 | |
19 class SweptSineSource { | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
How about some commentary?
DaleCurtis
2012/07/10 01:00:25
Done.
| |
20 public: | |
21 SweptSineSource(int sample_rate, int output_samples, double max_frequency) | |
22 : sample_rate_(sample_rate), | |
23 total_output_samples_(output_samples), | |
24 min_frequency_(kMinFrequency), | |
25 max_frequency_(max_frequency), | |
26 frequency_(min_frequency_), | |
27 phase_(0) { | |
28 } | |
29 | |
30 virtual ~SweptSineSource() {} | |
31 | |
32 void ProvideInput(float* destination, int frames) { | |
33 for (int i = 0; i < frames; ++i) { | |
34 // Filter out frequencies higher than Nyquist. | |
35 if (frequency_ > 0.5 * sample_rate_) { | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
is this not always max_frequency_?
DaleCurtis
2012/07/10 01:00:25
No, per Chris max_frequency is the nyquist limit o
| |
36 destination[i] = 0; | |
37 } else { | |
38 destination[i] = sin(phase_); | |
39 phase_ += 2 * M_PI * frequency_ / sample_rate_; | |
40 frequency_ += (max_frequency_ - min_frequency_) / total_output_samples_; | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
FWIW, ISTM the RHS here is a ctor-time constant, s
DaleCurtis
2012/07/10 01:00:25
Cleaned this up a bit using Chris's new method.
| |
41 } | |
42 } | |
43 } | |
44 | |
45 private: | |
46 static const int kMinFrequency = 5; | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
enum
DaleCurtis
2012/07/10 01:00:25
Done.
| |
47 | |
48 double sample_rate_; | |
49 int total_output_samples_; | |
50 double min_frequency_; | |
51 double max_frequency_; | |
52 double frequency_; | |
53 double phase_; | |
54 | |
55 DISALLOW_COPY_AND_ASSIGN(SweptSineSource); | |
56 }; | |
57 | |
58 typedef std::tr1::tuple<int, int, double, double, double> SincResamplerTestData; | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
Chromium's Tuple class is slightly less ugly to wo
DaleCurtis
2012/07/10 01:00:25
I thought of that, but I think this ends up being
| |
59 class SincResamplerTestCase | |
60 : public testing::TestWithParam<SincResamplerTestData> { | |
61 public: | |
62 SincResamplerTestCase() | |
63 : input_rate_(std::tr1::get<0>(GetParam())), | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
using?
DaleCurtis
2012/07/10 01:00:25
Clearer this way I think.
| |
64 output_rate_(std::tr1::get<1>(GetParam())), | |
65 rms_error_(std::tr1::get<2>(GetParam())), | |
66 low_freq_error_(std::tr1::get<3>(GetParam())), | |
67 high_freq_error_(std::tr1::get<4>(GetParam())) { | |
68 } | |
69 | |
70 virtual ~SincResamplerTestCase() {} | |
71 | |
72 protected: | |
73 int input_rate_; | |
74 int output_rate_; | |
75 double rms_error_; | |
76 double low_freq_error_; | |
77 double high_freq_error_; | |
78 }; | |
79 | |
80 // Tests resampling using a given input and output sample rate. | |
81 TEST_P(SincResamplerTestCase, Resample) { | |
82 // Make comparisons using one second of data. | |
83 static const int kTestDurationSecs = 1; | |
84 int input_samples = kTestDurationSecs * input_rate_; | |
85 int output_samples = kTestDurationSecs * output_rate_; | |
86 | |
87 // Nyquist frequency for the input sampling rate. | |
88 double input_nyquist_freq = 0.5 * input_rate_; | |
89 | |
90 // Source for data to be resampled. | |
91 SweptSineSource resampler_source( | |
92 input_rate_, input_samples, input_nyquist_freq); | |
93 | |
94 SincResampler resampler( | |
95 base::Bind( | |
96 &SweptSineSource::ProvideInput, base::Unretained(&resampler_source)), | |
97 input_rate_ / static_cast<double>(output_rate_)); | |
98 | |
99 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to | |
100 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. | |
101 scoped_array<float> resampled_destination(new float[output_samples]); | |
102 scoped_array<float> pure_destination(new float[output_samples]); | |
103 | |
104 // Generate resampled signal. | |
105 resampler.Resample(resampled_destination.get(), output_samples); | |
106 | |
107 // Generate pure signal. | |
108 SweptSineSource pure_source( | |
109 output_rate_, output_samples, input_nyquist_freq); | |
110 pure_source.ProvideInput(pure_destination.get(), output_samples); | |
111 | |
112 // TODO(dalecurtis): Figure out what we need to do here w/ crogers. | |
113 // // Calculate Root-Mean-Square-Error for the resampling. | |
114 // double sum_of_squares = 0; | |
115 // double max_error = 0; | |
116 // for (int i = 0; i < output_samples; ++i) { | |
117 // double error = fabs(resampled_destination[i] - pure_destination[i]); | |
118 // max_error = std::max(error, max_error); | |
119 // sum_of_squares += error * error; | |
120 // } | |
121 | |
122 // double rms_error = sqrt(sum_of_squares / output_samples); | |
123 | |
124 // EXPECT_LT(rms_error, rms_error_); | |
125 // EXPECT_LT(max_error, low_freq_error_); | |
126 // EXPECT_LT(max_error, high_freq_error_); | |
127 } | |
128 | |
129 INSTANTIATE_TEST_CASE_P( | |
130 SincResamplerTest, SincResamplerTestCase, testing::Values( | |
131 // To 44.1kHz | |
132 std::tr1::make_tuple(8000, 44100, 0, 0, 0), | |
Ami GONE FROM CHROMIUM
2012/07/03 20:54:42
I guess these 0,0,0's are placeholders that won't
DaleCurtis
2012/07/10 01:00:25
Correct.
| |
133 std::tr1::make_tuple(11025, 44100, 0, 0, 0), | |
134 std::tr1::make_tuple(16000, 44100, 0, 0, 0), | |
135 std::tr1::make_tuple(22050, 44100, 0, 0, 0), | |
136 std::tr1::make_tuple(32000, 44100, 0, 0, 0), | |
137 std::tr1::make_tuple(44100, 44100, 0, 0, 0), | |
138 std::tr1::make_tuple(48000, 44100, 0, 0, 0), | |
139 std::tr1::make_tuple(96000, 44100, 0, 0, 0), | |
140 std::tr1::make_tuple(192000, 44100, 0, 0, 0), | |
141 | |
142 // To 48kHz | |
143 std::tr1::make_tuple(8000, 48000, 0, 0, 0), | |
144 std::tr1::make_tuple(11025, 48000, 0, 0, 0), | |
145 std::tr1::make_tuple(16000, 48000, 0, 0, 0), | |
146 std::tr1::make_tuple(22050, 48000, 0, 0, 0), | |
147 std::tr1::make_tuple(32000, 48000, 0, 0, 0), | |
148 std::tr1::make_tuple(44100, 48000, 0, 0, 0), | |
149 std::tr1::make_tuple(48000, 48000, 0, 0, 0), | |
150 std::tr1::make_tuple(96000, 48000, 0, 0, 0), | |
151 std::tr1::make_tuple(192000, 48000, 0, 0, 0), | |
152 | |
153 // To 96kHz | |
154 std::tr1::make_tuple(8000, 96000, 0, 0, 0), | |
155 std::tr1::make_tuple(11025, 96000, 0, 0, 0), | |
156 std::tr1::make_tuple(16000, 96000, 0, 0, 0), | |
157 std::tr1::make_tuple(22050, 96000, 0, 0, 0), | |
158 std::tr1::make_tuple(32000, 96000, 0, 0, 0), | |
159 std::tr1::make_tuple(44100, 96000, 0, 0, 0), | |
160 std::tr1::make_tuple(48000, 96000, 0, 0, 0), | |
161 std::tr1::make_tuple(96000, 96000, 0, 0, 0), | |
162 std::tr1::make_tuple(192000, 96000, 0, 0, 0), | |
163 | |
164 // To 192kHz | |
165 std::tr1::make_tuple(8000, 192000, 0, 0, 0), | |
166 std::tr1::make_tuple(11025, 192000, 0, 0, 0), | |
167 std::tr1::make_tuple(16000, 192000, 0, 0, 0), | |
168 std::tr1::make_tuple(22050, 192000, 0, 0, 0), | |
169 std::tr1::make_tuple(32000, 192000, 0, 0, 0), | |
170 std::tr1::make_tuple(44100, 192000, 0, 0, 0), | |
171 std::tr1::make_tuple(48000, 192000, 0, 0, 0), | |
172 std::tr1::make_tuple(96000, 192000, 0, 0, 0), | |
173 std::tr1::make_tuple(192000, 192000, 0, 0, 0))); | |
174 | |
175 } // namespace media | |
OLD | NEW |