| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2012 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 <cmath> | |
| 12 #include <cstdio> | |
| 13 | |
| 14 #include <algorithm> | |
| 15 | |
| 16 #include "gflags/gflags.h" | |
| 17 #include "testing/gtest/include/gtest/gtest.h" | |
| 18 #include "webrtc/modules/audio_processing/agc/agc.h" | |
| 19 #include "webrtc/modules/audio_processing/agc/utility.h" | |
| 20 #include "webrtc/modules/audio_processing/include/audio_processing.h" | |
| 21 #include "webrtc/modules/interface/module_common_types.h" | |
| 22 #include "webrtc/system_wrappers/interface/logging.h" | |
| 23 #include "webrtc/test/testsupport/trace_to_stderr.h" | |
| 24 #include "webrtc/tools/agc/agc_manager.h" | |
| 25 #include "webrtc/tools/agc/test_utils.h" | |
| 26 #include "webrtc/voice_engine/mock/fake_voe_external_media.h" | |
| 27 #include "webrtc/voice_engine/mock/mock_voe_volume_control.h" | |
| 28 | |
| 29 DEFINE_string(in, "in.pcm", "input filename"); | |
| 30 DEFINE_string(out, "out.pcm", "output filename"); | |
| 31 DEFINE_int32(rate, 16000, "sample rate in Hz"); | |
| 32 DEFINE_int32(channels, 1, "number of channels"); | |
| 33 DEFINE_int32(level, -18, "target level in RMS dBFs [-100, 0]"); | |
| 34 DEFINE_bool(limiter, true, "enable a limiter for the compression stage"); | |
| 35 DEFINE_int32(cmp_level, 2, "target level in dBFs for the compression stage"); | |
| 36 DEFINE_int32(mic_gain, 80, "range of gain provided by the virtual mic in dB"); | |
| 37 DEFINE_int32(gain_offset, 0, | |
| 38 "an amount (in dB) to add to every entry in the gain map"); | |
| 39 DEFINE_string(gain_file, "", | |
| 40 "filename providing a mic gain mapping. The file should be text containing " | |
| 41 "a (floating-point) gain entry in dBFs per line corresponding to levels " | |
| 42 "from 0 to 255."); | |
| 43 | |
| 44 using ::testing::_; | |
| 45 using ::testing::ByRef; | |
| 46 using ::testing::DoAll; | |
| 47 using ::testing::Mock; | |
| 48 using ::testing::Return; | |
| 49 using ::testing::SaveArg; | |
| 50 using ::testing::SetArgReferee; | |
| 51 | |
| 52 namespace webrtc { | |
| 53 namespace { | |
| 54 | |
| 55 const char kUsage[] = "\nProcess an audio file to simulate an analog agc."; | |
| 56 | |
| 57 void ReadGainMapFromFile(FILE* file, int offset, int gain_map[256]) { | |
| 58 for (int i = 0; i < 256; ++i) { | |
| 59 float gain = 0; | |
| 60 ASSERT_EQ(1, fscanf(file, "%f", &gain)); | |
| 61 gain_map[i] = std::floor(gain + 0.5); | |
| 62 } | |
| 63 | |
| 64 // Adjust from dBFs to gain in dB. We assume that level 127 provides 0 dB | |
| 65 // gain. This corresponds to the interpretation in MicLevel2Gain(). | |
| 66 const int midpoint = gain_map[127]; | |
| 67 printf("Gain map\n"); | |
| 68 for (int i = 0; i < 256; ++i) { | |
| 69 gain_map[i] += offset - midpoint; | |
| 70 if (i % 5 == 0) { | |
| 71 printf("%d: %d dB\n", i, gain_map[i]); | |
| 72 } | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 void CalculateGainMap(int gain_range_db, int offset, int gain_map[256]) { | |
| 77 printf("Gain map\n"); | |
| 78 for (int i = 0; i < 256; ++i) { | |
| 79 gain_map[i] = std::floor(MicLevel2Gain(gain_range_db, i) + 0.5) + offset; | |
| 80 if (i % 5 == 0) { | |
| 81 printf("%d: %d dB\n", i, gain_map[i]); | |
| 82 } | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 void RunAgc() { | |
| 87 test::TraceToStderr trace_to_stderr(true); | |
| 88 FILE* in_file = fopen(FLAGS_in.c_str(), "rb"); | |
| 89 ASSERT_TRUE(in_file != NULL); | |
| 90 FILE* out_file = fopen(FLAGS_out.c_str(), "wb"); | |
| 91 ASSERT_TRUE(out_file != NULL); | |
| 92 | |
| 93 int gain_map[256]; | |
| 94 if (!FLAGS_gain_file.empty()) { | |
| 95 FILE* gain_file = fopen(FLAGS_gain_file.c_str(), "rt"); | |
| 96 ASSERT_TRUE(gain_file != NULL); | |
| 97 ReadGainMapFromFile(gain_file, FLAGS_gain_offset, gain_map); | |
| 98 fclose(gain_file); | |
| 99 } else { | |
| 100 CalculateGainMap(FLAGS_mic_gain, FLAGS_gain_offset, gain_map); | |
| 101 } | |
| 102 | |
| 103 FakeVoEExternalMedia media; | |
| 104 MockVoEVolumeControl volume; | |
| 105 Agc* agc = new Agc; | |
| 106 AudioProcessing* audioproc = AudioProcessing::Create(); | |
| 107 ASSERT_TRUE(audioproc != NULL); | |
| 108 AgcManager manager(&media, &volume, agc, audioproc); | |
| 109 | |
| 110 int mic_level = 128; | |
| 111 int last_mic_level = mic_level; | |
| 112 EXPECT_CALL(volume, GetMicVolume(_)) | |
| 113 .WillRepeatedly(DoAll(SetArgReferee<0>(ByRef(mic_level)), Return(0))); | |
| 114 EXPECT_CALL(volume, SetMicVolume(_)) | |
| 115 .WillRepeatedly(DoAll(SaveArg<0>(&mic_level), Return(0))); | |
| 116 | |
| 117 manager.Enable(true); | |
| 118 ASSERT_EQ(0, agc->set_target_level_dbfs(FLAGS_level)); | |
| 119 const AudioProcessing::Error kNoErr = AudioProcessing::kNoError; | |
| 120 GainControl* gctrl = audioproc->gain_control(); | |
| 121 ASSERT_EQ(kNoErr, gctrl->set_target_level_dbfs(FLAGS_cmp_level)); | |
| 122 ASSERT_EQ(kNoErr, gctrl->enable_limiter(FLAGS_limiter)); | |
| 123 | |
| 124 AudioFrame frame; | |
| 125 frame.num_channels_ = FLAGS_channels; | |
| 126 frame.sample_rate_hz_ = FLAGS_rate; | |
| 127 frame.samples_per_channel_ = FLAGS_rate / 100; | |
| 128 const size_t frame_length = frame.samples_per_channel_ * FLAGS_channels; | |
| 129 size_t sample_count = 0; | |
| 130 while (fread(frame.data_, sizeof(int16_t), frame_length, in_file) == | |
| 131 frame_length) { | |
| 132 SimulateMic(gain_map, mic_level, last_mic_level, &frame); | |
| 133 last_mic_level = mic_level; | |
| 134 media.CallProcess(kRecordingAllChannelsMixed, frame.data_, | |
| 135 frame.samples_per_channel_, FLAGS_rate, FLAGS_channels); | |
| 136 ASSERT_EQ(frame_length, | |
| 137 fwrite(frame.data_, sizeof(int16_t), frame_length, out_file)); | |
| 138 sample_count += frame_length; | |
| 139 trace_to_stderr.SetTimeSeconds(static_cast<float>(sample_count) / | |
| 140 FLAGS_channels / FLAGS_rate); | |
| 141 } | |
| 142 fclose(in_file); | |
| 143 fclose(out_file); | |
| 144 EXPECT_CALL(volume, Release()); | |
| 145 } | |
| 146 | |
| 147 } // namespace | |
| 148 } // namespace webrtc | |
| 149 | |
| 150 int main(int argc, char* argv[]) { | |
| 151 google::SetUsageMessage(webrtc::kUsage); | |
| 152 google::ParseCommandLineFlags(&argc, &argv, true); | |
| 153 webrtc::RunAgc(); | |
| 154 return 0; | |
| 155 } | |
| OLD | NEW |