Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 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 | |
| 5 #include <cmath> | |
| 6 #include <cstdint> | |
| 7 #include <limits> | |
| 8 #include <string> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "base/memory/ptr_util.h" | |
| 14 #include "chromecast/media/cma/backend/alsa/slew_volume.h" | |
| 15 #include "media/base/audio_bus.h" | |
| 16 #include "media/base/vector_math.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 | |
| 19 namespace chromecast { | |
| 20 namespace media { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 const int kNumChannels = 2; | |
| 25 const int kNumFrames = 100; | |
| 26 const float kSinFrequency = 1.0f / kNumFrames; | |
| 27 const int kBytesPerSample = sizeof(int32_t); | |
| 28 | |
| 29 // Frequency is in frames (frequency = frequency_in_hz / sample rate) | |
| 30 std::unique_ptr<::media::AudioBus> GetSineData(size_t frames, float frequency) { | |
| 31 auto data = ::media::AudioBus::Create(kNumChannels, frames); | |
| 32 std::vector<int32_t> sine(frames * 2); | |
| 33 for (size_t i = 0; i < frames; ++i) { | |
| 34 // Offset by 1 because sin(0) = 0 and the first value is a special case. | |
| 35 sine[i * 2] = sin(static_cast<float>(i + 1) * frequency * 2 * M_PI) * | |
| 36 std::numeric_limits<int32_t>::max(); | |
| 37 sine[i * 2 + 1] = cos(static_cast<float>(i + 1) * frequency * 2 * M_PI) * | |
| 38 std::numeric_limits<int32_t>::max(); | |
| 39 } | |
| 40 data->FromInterleaved(sine.data(), frames, kBytesPerSample); | |
| 41 return data; | |
| 42 } | |
| 43 | |
| 44 // Gets pointers to the data in an audiobus. | |
| 45 // If |swapped| is true, the channel order will be swapped. | |
| 46 std::vector<float*> GetDataChannels(::media::AudioBus* audio, | |
| 47 bool swapped = false) { | |
| 48 std::vector<float*> data(kNumChannels); | |
| 49 for (int i = 0; i < kNumChannels; ++i) { | |
| 50 int source_channel = swapped ? (i + 1) % kNumChannels : i; | |
| 51 data[i] = audio->channel(source_channel); | |
| 52 } | |
| 53 return data; | |
| 54 } | |
| 55 | |
| 56 void ScaleData(const std::vector<float*>& data, int frames, float scale) { | |
| 57 for (size_t ch = 0; ch < data.size(); ++ch) { | |
| 58 for (int f = 0; f < frames; ++f) { | |
| 59 data[ch][f] *= scale; | |
| 60 } | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 void CompareDataPartial(const std::vector<float*>& expected, | |
| 65 const std::vector<float*>& actual, | |
| 66 int start, | |
| 67 int end) { | |
| 68 ASSERT_GE(start, 0); | |
| 69 ASSERT_LT(start, end); | |
| 70 ASSERT_EQ(expected.size(), actual.size()); | |
| 71 | |
| 72 for (size_t ch = 0; ch < expected.size(); ++ch) { | |
| 73 for (int f = start; f < end; ++f) { | |
| 74 EXPECT_FLOAT_EQ(expected[ch][f], actual[ch][f]) | |
| 75 << "ch: " << ch << " f: " << f; | |
| 76 } | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 } // namespace | |
| 81 | |
| 82 class SlewVolumeBaseTest : public ::testing::Test { | |
| 83 protected: | |
| 84 SlewVolumeBaseTest() = default; | |
| 85 ~SlewVolumeBaseTest() override = default; | |
| 86 | |
| 87 void SetUp() override { | |
| 88 slew_volume_ = base::MakeUnique<SlewVolume>(); | |
| 89 slew_volume_->Interrupted(); | |
| 90 MakeData(kNumFrames); | |
| 91 } | |
| 92 | |
| 93 void MakeData(int num_frames) { | |
| 94 num_frames_ = num_frames; | |
| 95 data_bus_ = GetSineData(num_frames_, kSinFrequency); | |
| 96 data_bus_2_ = GetSineData(num_frames_, kSinFrequency); | |
| 97 expected_bus_ = GetSineData(num_frames_, kSinFrequency); | |
| 98 data_ = GetDataChannels(data_bus_.get()); | |
| 99 data_2_ = GetDataChannels(data_bus_2_.get(), true /* swapped */); | |
| 100 expected_ = GetDataChannels(expected_bus_.get()); | |
| 101 } | |
| 102 | |
| 103 void CompareBuffers(int start = 0, int end = -1) { | |
| 104 if (end == -1) { | |
| 105 end = num_frames_; | |
| 106 } | |
| 107 ASSERT_LE(end, num_frames_); | |
|
bcf
2017/05/04 03:45:06
ASSERT_GE(end, 0)
bshaya
2017/05/04 18:15:41
Done.
| |
| 108 CompareDataPartial(expected_, data_, start, end); | |
| 109 } | |
| 110 | |
| 111 void ClearInterrupted() { | |
| 112 float throwaway __attribute__((__aligned__(16))) = 0.0f; | |
| 113 slew_volume_->ProcessFMUL(false, &throwaway, 1, &throwaway); | |
| 114 } | |
| 115 | |
| 116 int num_frames_; | |
| 117 | |
| 118 std::unique_ptr<SlewVolume> slew_volume_; | |
| 119 std::unique_ptr<::media::AudioBus> data_bus_; | |
| 120 std::unique_ptr<::media::AudioBus> data_bus_2_; | |
| 121 std::unique_ptr<::media::AudioBus> expected_bus_; | |
| 122 std::vector<float*> data_; | |
| 123 std::vector<float*> data_2_; | |
| 124 std::vector<float*> expected_; | |
| 125 | |
| 126 private: | |
| 127 DISALLOW_COPY_AND_ASSIGN(SlewVolumeBaseTest); | |
| 128 }; | |
| 129 | |
| 130 TEST_F(SlewVolumeBaseTest, BadSampleRate) { | |
| 131 ASSERT_DEATH(slew_volume_->SetSampleRate(0), "sample_rate"); | |
| 132 } | |
| 133 | |
| 134 TEST_F(SlewVolumeBaseTest, BadSlewTime) { | |
| 135 ASSERT_DEATH(slew_volume_->SetMaxSlewTimeMs(-1), ""); | |
| 136 } | |
| 137 | |
| 138 class SlewVolumeSteadyStateTest : public SlewVolumeBaseTest { | |
| 139 protected: | |
| 140 SlewVolumeSteadyStateTest() = default; | |
| 141 ~SlewVolumeSteadyStateTest() override = default; | |
| 142 | |
| 143 void SetUp() override { | |
| 144 SlewVolumeBaseTest::SetUp(); | |
| 145 slew_volume_->Interrupted(); | |
| 146 } | |
| 147 | |
| 148 private: | |
| 149 DISALLOW_COPY_AND_ASSIGN(SlewVolumeSteadyStateTest); | |
| 150 }; | |
| 151 | |
| 152 TEST_F(SlewVolumeSteadyStateTest, FMULNoOp) { | |
| 153 slew_volume_->SetVolume(1.0f); | |
| 154 | |
| 155 slew_volume_->ProcessFMUL(false /* repeat transition */, data_[0], | |
| 156 num_frames_, data_[0]); | |
| 157 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1], num_frames_, | |
| 158 data_[1]); | |
| 159 CompareBuffers(); | |
| 160 } | |
| 161 | |
| 162 TEST_F(SlewVolumeSteadyStateTest, FMULCopy) { | |
| 163 slew_volume_->SetVolume(1.0f); | |
| 164 | |
| 165 slew_volume_->ProcessFMUL(false /* repeat transition */, data_2_[0], | |
| 166 num_frames_, data_[0]); | |
| 167 slew_volume_->ProcessFMUL(true /* repeat transition */, data_2_[1], | |
| 168 num_frames_, data_[1]); | |
| 169 CompareDataPartial(data_2_, data_, 0, num_frames_); | |
| 170 } | |
| 171 | |
| 172 TEST_F(SlewVolumeSteadyStateTest, FMULZero) { | |
| 173 slew_volume_->SetVolume(0.0f); | |
| 174 slew_volume_->ProcessFMUL(false, /* repeat transition */ | |
| 175 data_[0], num_frames_, data_[0]); | |
| 176 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1], num_frames_, | |
| 177 data_[1]); | |
| 178 | |
| 179 for (size_t ch = 0; ch < data_.size(); ++ch) { | |
| 180 for (int f = 0; f < num_frames_; ++f) { | |
| 181 EXPECT_EQ(0.0f, data_[ch][f]) << "at ch " << ch << "frame " << f; | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 TEST_F(SlewVolumeSteadyStateTest, FMULInterrupted) { | |
| 187 float volume = 0.6f; | |
| 188 slew_volume_->SetVolume(volume); | |
| 189 | |
| 190 slew_volume_->ProcessFMUL(false /* repeat transition */, | |
| 191 data_[0] /* source */, num_frames_, | |
| 192 data_[0] /* dst */); | |
| 193 slew_volume_->ProcessFMUL(true /* repeat transition */, data_[1] /* source */, | |
| 194 num_frames_, data_[1] /* dst */); | |
| 195 ScaleData(expected_, num_frames_, volume); | |
| 196 CompareBuffers(); | |
| 197 } | |
| 198 | |
| 199 TEST_F(SlewVolumeSteadyStateTest, FMACNoOp) { | |
| 200 slew_volume_->SetVolume(0.0f); | |
| 201 slew_volume_->ProcessFMAC(false /* repeat transition */, | |
| 202 data_2_[0] /* source */, num_frames_, | |
| 203 data_[0] /* dst */); | |
| 204 slew_volume_->ProcessFMAC(false /* repeat transition */, | |
| 205 data_2_[1] /* source */, num_frames_, | |
| 206 data_[1] /*dst */); | |
| 207 CompareBuffers(); | |
| 208 } | |
| 209 | |
| 210 class SlewVolumeDynamicTest | |
| 211 : public SlewVolumeBaseTest, | |
| 212 public ::testing::WithParamInterface<std::tuple<int, int>> { | |
| 213 protected: | |
| 214 SlewVolumeDynamicTest() = default; | |
| 215 ~SlewVolumeDynamicTest() override = default; | |
| 216 | |
| 217 void SetUp() override { | |
| 218 SlewVolumeBaseTest::SetUp(); | |
| 219 sample_rate_ = std::get<0>(GetParam()); | |
| 220 slew_time_ms_ = std::get<1>(GetParam()); | |
| 221 slew_time_frames_ = sample_rate_ * slew_time_ms_ / 1000; | |
| 222 slew_volume_->SetSampleRate(sample_rate_); | |
| 223 slew_volume_->SetMaxSlewTimeMs(slew_time_ms_); | |
| 224 | |
| 225 int num_frames = slew_time_frames_ + 2; // +2 frames for numeric errors. | |
| 226 ASSERT_GE(num_frames, 1); | |
| 227 MakeData(num_frames); | |
| 228 } | |
| 229 | |
| 230 // Checks data_ = slew_volume_(expected_) | |
| 231 void CheckSlewMUL(double start_vol, double end_vol) { | |
| 232 for (size_t ch = 0; ch < data_.size(); ++ch) { | |
| 233 // First value should have original scaling applied. | |
| 234 EXPECT_FLOAT_EQ(expected_[ch][0] * start_vol, data_[ch][0]) << ch; | |
| 235 | |
| 236 // Steady state have final scaling applied | |
| 237 int f = num_frames_ - 1; | |
| 238 EXPECT_FLOAT_EQ(expected_[ch][f] * end_vol, data_[ch][f]) << ch; | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 // Checks data_ = expected_ + slew_volume_(data_2_) | |
| 243 void CheckSlewMAC(double start_vol, double end_vol) { | |
| 244 for (size_t ch = 0; ch < data_.size(); ++ch) { | |
| 245 // First value should have original scaling applied. | |
| 246 EXPECT_FLOAT_EQ(expected_[ch][0] + data_2_[ch][0] * start_vol, | |
| 247 data_[ch][0]) | |
| 248 << ch; | |
| 249 | |
| 250 // Steady state have final scaling applied | |
| 251 int f = num_frames_ - 1; | |
| 252 EXPECT_FLOAT_EQ(expected_[ch][f] + data_2_[ch][f] * end_vol, data_[ch][f]) | |
| 253 << ch << " " << f; | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 int sample_rate_; | |
| 258 int slew_time_ms_; | |
| 259 int slew_time_frames_; | |
| 260 | |
| 261 private: | |
| 262 DISALLOW_COPY_AND_ASSIGN(SlewVolumeDynamicTest); | |
| 263 }; | |
| 264 | |
| 265 TEST_P(SlewVolumeDynamicTest, FMULRampUp) { | |
| 266 double start = 0.0; | |
| 267 double end = 1.0; | |
| 268 slew_volume_->SetVolume(start); | |
| 269 ClearInterrupted(); | |
| 270 | |
| 271 slew_volume_->SetVolume(end); | |
| 272 slew_volume_->ProcessFMUL(false, data_[0], num_frames_, data_[0]); | |
| 273 slew_volume_->ProcessFMUL(true, data_[1], num_frames_, data_[1]); | |
| 274 CheckSlewMUL(start, end); | |
| 275 } | |
| 276 | |
| 277 TEST_P(SlewVolumeDynamicTest, FMULRampDown) { | |
| 278 double start = 1.0; | |
| 279 double end = 0.0; | |
| 280 slew_volume_->SetVolume(start); | |
| 281 ClearInterrupted(); | |
| 282 | |
| 283 slew_volume_->SetVolume(end); | |
| 284 slew_volume_->ProcessFMUL(false, data_[0], num_frames_, data_[0]); | |
| 285 slew_volume_->ProcessFMUL(true, data_[1], num_frames_, data_[1]); | |
| 286 CheckSlewMUL(start, end); | |
| 287 } | |
| 288 | |
| 289 // Provide data as small buffers. | |
| 290 TEST_P(SlewVolumeDynamicTest, FMULRampDownByParts) { | |
| 291 double start = 1.0; | |
| 292 double end = 0.0; | |
| 293 slew_volume_->SetVolume(start); | |
| 294 ClearInterrupted(); | |
| 295 | |
| 296 slew_volume_->SetVolume(end); | |
| 297 int frame_step = ::media::vector_math::kRequiredAlignment / kBytesPerSample; | |
| 298 int f; | |
| 299 for (f = 0; f < num_frames_; f += frame_step) { | |
| 300 // Process any remaining samples in the last step. | |
| 301 if (num_frames_ - f < frame_step * 2) { | |
| 302 frame_step = num_frames_ - f; | |
| 303 } | |
| 304 slew_volume_->ProcessFMUL(false, expected_[0] + f, frame_step, | |
| 305 data_[0] + f); | |
| 306 slew_volume_->ProcessFMUL(true, expected_[1] + f, frame_step, data_[1] + f); | |
| 307 } | |
| 308 ASSERT_EQ(num_frames_, f); | |
| 309 CheckSlewMUL(start, end); | |
| 310 } | |
| 311 | |
| 312 TEST_P(SlewVolumeDynamicTest, FMACRampUp) { | |
| 313 double start = 0.0; | |
| 314 double end = 1.0; | |
| 315 slew_volume_->SetVolume(start); | |
| 316 ClearInterrupted(); | |
| 317 | |
| 318 slew_volume_->SetVolume(end); | |
| 319 slew_volume_->ProcessFMAC(false, data_2_[0], num_frames_, data_[0]); | |
| 320 slew_volume_->ProcessFMAC(true, data_2_[1], num_frames_, data_[1]); | |
| 321 CheckSlewMAC(start, end); | |
| 322 } | |
| 323 | |
| 324 TEST_P(SlewVolumeDynamicTest, FMACRampDown) { | |
| 325 double start = 1.0; | |
| 326 double end = 0.0; | |
| 327 slew_volume_->SetVolume(start); | |
| 328 ClearInterrupted(); | |
| 329 | |
| 330 slew_volume_->SetVolume(end); | |
| 331 slew_volume_->ProcessFMAC(false, data_2_[0], num_frames_, data_[0]); | |
| 332 slew_volume_->ProcessFMAC(true, data_2_[1], num_frames_, data_[1]); | |
| 333 CheckSlewMAC(start, end); | |
| 334 } | |
| 335 | |
| 336 // Provide data as small buffers. | |
| 337 TEST_P(SlewVolumeDynamicTest, FMACRampUpByParts) { | |
| 338 double start = 0.0; | |
| 339 double end = 1.0; | |
| 340 slew_volume_->SetVolume(start); | |
| 341 ClearInterrupted(); | |
| 342 | |
| 343 slew_volume_->SetVolume(end); | |
| 344 int frame_step = ::media::vector_math::kRequiredAlignment / kBytesPerSample; | |
| 345 int f; | |
| 346 for (f = 0; f < num_frames_; f += frame_step) { | |
| 347 // Process any remaining samples in the last step. | |
| 348 if (num_frames_ - f < frame_step * 2) { | |
| 349 frame_step = num_frames_ - f; | |
| 350 } | |
| 351 slew_volume_->ProcessFMAC(false, data_2_[0] + f, frame_step, data_[0] + f); | |
| 352 slew_volume_->ProcessFMAC(true, data_2_[1] + f, frame_step, data_[1] + f); | |
| 353 } | |
| 354 ASSERT_EQ(num_frames_, f); | |
| 355 CheckSlewMAC(start, end); | |
| 356 } | |
| 357 | |
| 358 INSTANTIATE_TEST_CASE_P(SingleBufferSlew, | |
| 359 SlewVolumeDynamicTest, | |
| 360 ::testing::Combine(::testing::Values(44100, 48000), | |
| 361 ::testing::Values(0, 15, 100))); | |
| 362 } // namespace media | |
| 363 } // namespace chromecast | |
| OLD | NEW |