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