OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2017 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 <sstream> |
| 12 #include <string> |
| 13 #include <vector> |
| 14 |
| 15 #include "webrtc/base/array_view.h" |
| 16 #include "webrtc/modules/audio_processing/test/fake_recording_device.h" |
| 17 #include "webrtc/test/gtest.h" |
| 18 |
| 19 namespace webrtc { |
| 20 |
| 21 namespace { |
| 22 |
| 23 using MappingKind = FakeRecordingDevice::LevelToScalingMappingKind; |
| 24 |
| 25 // TODO(...): Add new mapping kinds here as they are added to |
| 26 // LevelToScalingMappingKind. |
| 27 const std::vector<MappingKind> kMappingKindsToTest = |
| 28 {MappingKind::kIdentity, MappingKind::kLinear}; |
| 29 |
| 30 const std::vector<std::vector<float>> kTestMultiChannelSamples{ |
| 31 std::vector<float>{-10.0, -1.0, -0.1, 0.0, 0.1, 1.0, 10.0}}; |
| 32 |
| 33 // Returns a vector of ArrayView items of const floats. |
| 34 std::vector<rtc::ArrayView<const float>> VecVecToVecArrayViewOfConst( |
| 35 const std::vector<std::vector<float>>& vectorOfVectors) { |
| 36 std::vector<rtc::ArrayView<const float>> vectorOfArrayViews; |
| 37 for (const auto& v : vectorOfVectors) { vectorOfArrayViews.emplace_back(v); } |
| 38 return vectorOfArrayViews; |
| 39 } |
| 40 |
| 41 // Returns a vector of ArrayView items of non-const floats. |
| 42 std::vector<rtc::ArrayView<float>> VecVecToVecArrayView( |
| 43 std::vector<std::vector<float>>* vectorOfVectors) { |
| 44 std::vector<rtc::ArrayView<float>> vectorOfArrayViews; |
| 45 for (auto& v : *vectorOfVectors) { vectorOfArrayViews.emplace_back(v); } |
| 46 return vectorOfArrayViews; |
| 47 } |
| 48 |
| 49 // Checks that the samples modified using monotonic level values are also |
| 50 // monotonic. |
| 51 void CheckIfMonotoneSamplesModules( |
| 52 const std::vector<rtc::ArrayView<float>>& prev, |
| 53 const std::vector<rtc::ArrayView<float>>& curr) { |
| 54 bool valid = true; |
| 55 for (size_t i = 0; i < prev.size(); ++i) { |
| 56 for (size_t j = 0; j < prev[i].size(); ++j) { |
| 57 valid = std::fabs(prev[i][j]) <= std::fabs(curr[i][j]); |
| 58 if (!valid) { break; } |
| 59 } |
| 60 if (!valid) { break; } |
| 61 } |
| 62 EXPECT_TRUE(valid); |
| 63 } |
| 64 |
| 65 // Checks that the samples in each pair have the same sign unless the sample in |
| 66 // |dst| is zero (because of zero gain). |
| 67 void CheckSameSign( |
| 68 const std::vector<rtc::ArrayView<const float>>& src, |
| 69 const std::vector<rtc::ArrayView<float>>& dst) { |
| 70 const auto fsgn = [](float x) { return ((x < 0) ? -1 : (x > 0) ? 1 : 0); }; |
| 71 bool valid = true; |
| 72 for (size_t i = 0; i < src.size(); ++i) { |
| 73 for (size_t j = 0; j < src[i].size(); ++j) { |
| 74 valid = dst[i][j] == 0.0f || fsgn(src[i][j]) == fsgn(dst[i][j]); |
| 75 if (!valid) { break; } |
| 76 } |
| 77 if (!valid) { break; } |
| 78 } |
| 79 EXPECT_TRUE(valid); |
| 80 } |
| 81 |
| 82 std::string MappingKindToString(MappingKind kind) { |
| 83 std::ostringstream ss; |
| 84 ss << "simulated microphone kind code: " << static_cast<size_t>(kind); |
| 85 return ss.str(); |
| 86 } |
| 87 |
| 88 std::string AnalogLevelToString(int level) { |
| 89 std::ostringstream ss; |
| 90 ss << "analog level: " << level; |
| 91 return ss.str(); |
| 92 } |
| 93 |
| 94 } // namespace |
| 95 |
| 96 TEST(AnalogVolumeMapper, CheckHelperFunctions) { |
| 97 // Check read. |
| 98 const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst( |
| 99 kTestMultiChannelSamples); |
| 100 EXPECT_EQ(kTestMultiChannelSamples[0][0], |
| 101 src_multichannel_samples_view[0][0]); |
| 102 |
| 103 // Check sizes. |
| 104 auto dst_multichannel_samples = kTestMultiChannelSamples; |
| 105 auto dst_multichannel_samples_view = VecVecToVecArrayView( |
| 106 &dst_multichannel_samples); |
| 107 EXPECT_EQ(kTestMultiChannelSamples.size(), // Same number of channels. |
| 108 dst_multichannel_samples_view.size()); |
| 109 EXPECT_EQ(kTestMultiChannelSamples[0].size(), // Same number of samples. |
| 110 dst_multichannel_samples_view[0].size()); |
| 111 |
| 112 // Check write. |
| 113 dst_multichannel_samples[0][1] = -5.0f; |
| 114 EXPECT_EQ(dst_multichannel_samples[0][0], |
| 115 dst_multichannel_samples_view[0][0]); |
| 116 } |
| 117 |
| 118 TEST(AnalogVolumeMapper, GainCurveShouldBeMonotone) { |
| 119 // Create test samples. |
| 120 const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst( |
| 121 kTestMultiChannelSamples); |
| 122 |
| 123 // Create output buffers. |
| 124 auto dst_multichannel_samples_prev = kTestMultiChannelSamples; |
| 125 auto dst_multichannel_samples_prev_view = VecVecToVecArrayView( |
| 126 &dst_multichannel_samples_prev); |
| 127 auto dst_multichannel_samples = kTestMultiChannelSamples; |
| 128 auto dst_multichannel_samples_view = VecVecToVecArrayView( |
| 129 &dst_multichannel_samples); |
| 130 |
| 131 // Test different mappings. |
| 132 for (const auto& kind : kMappingKindsToTest) { |
| 133 SCOPED_TRACE(MappingKindToString(kind)); |
| 134 webrtc::FakeRecordingDevice level_mapper(kind); |
| 135 |
| 136 // Apply lowest analog level. |
| 137 level_mapper.SimulateAnalogGain( |
| 138 src_multichannel_samples_view, dst_multichannel_samples_prev_view, 0); |
| 139 |
| 140 // Increment analog level to check monotonicity. |
| 141 for (int i = 1; i <= 255; ++i) { |
| 142 SCOPED_TRACE(AnalogLevelToString(i)); |
| 143 level_mapper.SimulateAnalogGain( |
| 144 src_multichannel_samples_view, dst_multichannel_samples_view, i); |
| 145 // TODO(alessiob): The test below is designed for state-less recording |
| 146 // devices. If, for instance, soft-clipping is used, the test might need |
| 147 // to be redesigned. |
| 148 CheckIfMonotoneSamplesModules( |
| 149 dst_multichannel_samples_prev_view, dst_multichannel_samples_view); |
| 150 |
| 151 // Update prev. |
| 152 dst_multichannel_samples_prev = dst_multichannel_samples; |
| 153 dst_multichannel_samples_prev_view = VecVecToVecArrayView( |
| 154 &dst_multichannel_samples_prev); |
| 155 } |
| 156 } |
| 157 } |
| 158 |
| 159 TEST(AnalogVolumeMapper, GainCurveShouldNotChangeSign) { |
| 160 // Create test samples. |
| 161 const auto src_multichannel_samples_view = VecVecToVecArrayViewOfConst( |
| 162 kTestMultiChannelSamples); |
| 163 |
| 164 // Create output buffer. |
| 165 auto dst_multichannel_samples = kTestMultiChannelSamples; |
| 166 auto dst_multichannel_samples_view = VecVecToVecArrayView( |
| 167 &dst_multichannel_samples); |
| 168 |
| 169 // Test different mappings. |
| 170 for (const auto& kind : kMappingKindsToTest) { |
| 171 SCOPED_TRACE(MappingKindToString(kind)); |
| 172 webrtc::FakeRecordingDevice level_mapper(kind); |
| 173 |
| 174 for (int i = 0; i <= 255; ++i) { |
| 175 SCOPED_TRACE(AnalogLevelToString(i)); |
| 176 level_mapper.SimulateAnalogGain( |
| 177 src_multichannel_samples_view, dst_multichannel_samples_view, i); |
| 178 // TODO(alessiob): The test below is designed for state-less recording |
| 179 // devices. If, for instance, soft-clipping is used, the test might need |
| 180 // to be redesigned. |
| 181 CheckSameSign( |
| 182 src_multichannel_samples_view, dst_multichannel_samples_view); |
| 183 } |
| 184 } |
| 185 } |
| 186 |
| 187 } // namespace webrtc |
OLD | NEW |