Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: webrtc/modules/audio_processing/test/audioproc_float.cc

Issue 1409943002: Add aecdump support to audioproc_f. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Add TickIntervalStats and clarify some documentation. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include <stdio.h> 11 #include <stdio.h>
12 #include <sstream> 12 #include <sstream>
13 #include <string> 13 #include <string>
14 14
15 #include "gflags/gflags.h" 15 #include "gflags/gflags.h"
16 #include "webrtc/base/checks.h" 16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/scoped_ptr.h" 17 #include "webrtc/base/scoped_ptr.h"
18 #include "webrtc/common_audio/channel_buffer.h" 18 #include "webrtc/common_audio/channel_buffer.h"
19 #include "webrtc/common_audio/wav_file.h" 19 #include "webrtc/common_audio/wav_file.h"
20 #include "webrtc/modules/audio_processing/include/audio_processing.h" 20 #include "webrtc/modules/audio_processing/include/audio_processing.h"
21 #include "webrtc/modules/audio_processing/test/audio_file_processor.h"
21 #include "webrtc/modules/audio_processing/test/protobuf_utils.h" 22 #include "webrtc/modules/audio_processing/test/protobuf_utils.h"
22 #include "webrtc/modules/audio_processing/test/test_utils.h" 23 #include "webrtc/modules/audio_processing/test/test_utils.h"
23 #include "webrtc/system_wrappers/interface/tick_util.h" 24 #include "webrtc/system_wrappers/interface/tick_util.h"
24 #include "webrtc/test/testsupport/trace_to_stderr.h" 25 #include "webrtc/test/testsupport/trace_to_stderr.h"
25 26
26 DEFINE_string(dump, "", "The name of the debug dump file to read from."); 27 DEFINE_string(dump, "", "Name of the aecdump debug file to read from.");
27 DEFINE_string(i, "", "The name of the input file to read from."); 28 DEFINE_string(i, "", "Name of the capture input stream file to read from.");
28 DEFINE_string(i_rev, "", "The name of the reverse input file to read from."); 29 DEFINE_string(
29 DEFINE_string(o, "out.wav", "Name of the output file to write to."); 30 o,
30 DEFINE_string(o_rev, 31 "out.wav",
31 "out_rev.wav", 32 "Name of the output file to write the processed capture stream to.");
32 "Name of the reverse output file to write to."); 33 DEFINE_int32(out_channels, 1, "Number of output channels.");
33 DEFINE_int32(out_channels, 0, "Number of output channels. Defaults to input."); 34 DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
34 DEFINE_int32(out_sample_rate, 0,
35 "Output sample rate in Hz. Defaults to input.");
36 DEFINE_string(mic_positions, "", 35 DEFINE_string(mic_positions, "",
37 "Space delimited cartesian coordinates of microphones in meters. " 36 "Space delimited cartesian coordinates of microphones in meters. "
38 "The coordinates of each point are contiguous. " 37 "The coordinates of each point are contiguous. "
39 "For a two element array: \"x1 y1 z1 x2 y2 z2\""); 38 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
40 39
41 DEFINE_bool(aec, false, "Enable echo cancellation."); 40 DEFINE_bool(aec, false, "Enable echo cancellation.");
42 DEFINE_bool(agc, false, "Enable automatic gain control."); 41 DEFINE_bool(agc, false, "Enable automatic gain control.");
43 DEFINE_bool(hpf, false, "Enable high-pass filtering."); 42 DEFINE_bool(hpf, false, "Enable high-pass filtering.");
44 DEFINE_bool(ns, false, "Enable noise suppression."); 43 DEFINE_bool(ns, false, "Enable noise suppression.");
45 DEFINE_bool(ts, false, "Enable transient suppression."); 44 DEFINE_bool(ts, false, "Enable transient suppression.");
(...skipping 10 matching lines...) Expand all
56 55
57 const int kChunksPerSecond = 100; 56 const int kChunksPerSecond = 100;
58 const char kUsage[] = 57 const char kUsage[] =
59 "Command-line tool to run audio processing on WAV files. Accepts either\n" 58 "Command-line tool to run audio processing on WAV files. Accepts either\n"
60 "an input capture WAV file or protobuf debug dump and writes to an output\n" 59 "an input capture WAV file or protobuf debug dump and writes to an output\n"
61 "WAV file.\n" 60 "WAV file.\n"
62 "\n" 61 "\n"
63 "All components are disabled by default. If any bi-directional components\n" 62 "All components are disabled by default. If any bi-directional components\n"
64 "are enabled, only debug dump files are permitted."; 63 "are enabled, only debug dump files are permitted.";
65 64
66 // Returns a StreamConfig corresponding to wav_file if it's non-nullptr.
67 // Otherwise returns a default initialized StreamConfig.
68 StreamConfig MakeStreamConfig(const WavFile* wav_file) {
69 if (wav_file) {
70 return {wav_file->sample_rate(), wav_file->num_channels()};
71 }
72 return {};
73 }
74
75 } // namespace 65 } // namespace
76 66
77 int main(int argc, char* argv[]) { 67 int main(int argc, char* argv[]) {
78 google::SetUsageMessage(kUsage); 68 google::SetUsageMessage(kUsage);
79 google::ParseCommandLineFlags(&argc, &argv, true); 69 google::ParseCommandLineFlags(&argc, &argv, true);
80 70
81 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) { 71 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
82 fprintf(stderr, 72 fprintf(stderr,
83 "An input file must be specified with either -i or -dump.\n"); 73 "An input file must be specified with either -i or -dump.\n");
84 return 1; 74 return 1;
85 } 75 }
86 if (!FLAGS_dump.empty()) { 76 if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) {
87 fprintf(stderr, "FIXME: the -dump option is not yet implemented.\n"); 77 fprintf(stderr, "-aec and -ie require a -dump file.\n");
78 return 1;
79 }
80 if (FLAGS_ts) {
81 fprintf(stderr,
82 "FIXME(ajm): The transient suppression output is not dumped.\n");
88 return 1; 83 return 1;
89 } 84 }
90 85
91 test::TraceToStderr trace_to_stderr(true); 86 test::TraceToStderr trace_to_stderr(true);
92 WavReader in_file(FLAGS_i);
93 // If the output format is uninitialized, use the input format.
94 const int out_channels =
95 FLAGS_out_channels ? FLAGS_out_channels : in_file.num_channels();
96 const int out_sample_rate =
97 FLAGS_out_sample_rate ? FLAGS_out_sample_rate : in_file.sample_rate();
98 WavWriter out_file(FLAGS_o, out_sample_rate, out_channels);
99
100 Config config; 87 Config config;
88 if (FLAGS_bf || FLAGS_all) {
89 if (FLAGS_mic_positions.empty()) {
90 fprintf(stderr, "-mic_positions must be specified when -bf is used.\n");
91 return 1;
92 }
93 config.Set<Beamforming>(
94 new Beamforming(true, ParseArrayGeometry(FLAGS_mic_positions)));
95 }
101 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all)); 96 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
102 config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all)); 97 config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all));
103 98
104 if (FLAGS_bf || FLAGS_all) {
105 const size_t num_mics = in_file.num_channels();
106 const std::vector<Point> array_geometry =
107 ParseArrayGeometry(FLAGS_mic_positions, num_mics);
108 RTC_CHECK_EQ(array_geometry.size(), num_mics);
109
110 config.Set<Beamforming>(new Beamforming(true, array_geometry));
111 }
112
113 rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config)); 99 rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
114 if (!FLAGS_dump.empty()) { 100 RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
115 RTC_CHECK_EQ(kNoErr,
116 ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
117 } else if (FLAGS_aec) {
118 fprintf(stderr, "-aec requires a -dump file.\n");
119 return -1;
120 }
121 bool process_reverse = !FLAGS_i_rev.empty();
122 RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all)); 101 RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
123 RTC_CHECK_EQ(kNoErr,
124 ap->gain_control()->set_mode(GainControl::kFixedDigital));
125 RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all)); 102 RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
126 RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all)); 103 RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
127 if (FLAGS_ns_level != -1) 104 if (FLAGS_ns_level != -1) {
128 RTC_CHECK_EQ(kNoErr, 105 RTC_CHECK_EQ(kNoErr,
129 ap->noise_suppression()->set_level( 106 ap->noise_suppression()->set_level(
130 static_cast<NoiseSuppression::Level>(FLAGS_ns_level))); 107 static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
131
132 printf("Input file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
133 FLAGS_i.c_str(), in_file.num_channels(), in_file.sample_rate());
134 printf("Output file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
135 FLAGS_o.c_str(), out_file.num_channels(), out_file.sample_rate());
136
137 ChannelBuffer<float> in_buf(
138 rtc::CheckedDivExact(in_file.sample_rate(), kChunksPerSecond),
139 in_file.num_channels());
140 ChannelBuffer<float> out_buf(
141 rtc::CheckedDivExact(out_file.sample_rate(), kChunksPerSecond),
142 out_file.num_channels());
143
144 std::vector<float> in_interleaved(in_buf.size());
145 std::vector<float> out_interleaved(out_buf.size());
146
147 rtc::scoped_ptr<WavReader> in_rev_file;
148 rtc::scoped_ptr<WavWriter> out_rev_file;
149 rtc::scoped_ptr<ChannelBuffer<float>> in_rev_buf;
150 rtc::scoped_ptr<ChannelBuffer<float>> out_rev_buf;
151 std::vector<float> in_rev_interleaved;
152 std::vector<float> out_rev_interleaved;
153 if (process_reverse) {
154 in_rev_file.reset(new WavReader(FLAGS_i_rev));
155 out_rev_file.reset(new WavWriter(FLAGS_o_rev, in_rev_file->sample_rate(),
156 in_rev_file->num_channels()));
157 printf("In rev file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
158 FLAGS_i_rev.c_str(), in_rev_file->num_channels(),
159 in_rev_file->sample_rate());
160 printf("Out rev file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
161 FLAGS_o_rev.c_str(), out_rev_file->num_channels(),
162 out_rev_file->sample_rate());
163 in_rev_buf.reset(new ChannelBuffer<float>(
164 rtc::CheckedDivExact(in_rev_file->sample_rate(), kChunksPerSecond),
165 in_rev_file->num_channels()));
166 in_rev_interleaved.resize(in_rev_buf->size());
167 out_rev_buf.reset(new ChannelBuffer<float>(
168 rtc::CheckedDivExact(out_rev_file->sample_rate(), kChunksPerSecond),
169 out_rev_file->num_channels()));
170 out_rev_interleaved.resize(out_rev_buf->size());
171 } 108 }
172 109
173 TickTime processing_start_time; 110 rtc::scoped_ptr<AudioFileProcessor> processor;
174 TickInterval accumulated_time; 111 auto out_file = rtc_make_scoped_ptr(
112 new WavWriter(FLAGS_o, FLAGS_out_sample_rate, FLAGS_out_channels));
113 if (FLAGS_dump.empty()) {
114 auto in_file = rtc_make_scoped_ptr(new WavReader(FLAGS_i));
115 processor.reset(
116 new WavFileProcessor(ap.Pass(), in_file.Pass(), out_file.Pass()));
117
118 } else {
119 processor.reset(new AecDumpFileProcessor(
120 ap.Pass(), fopen(FLAGS_dump.c_str(), "rb"), out_file.Pass()));
121 }
122
175 int num_chunks = 0; 123 int num_chunks = 0;
124 while (processor->ProcessAndWriteChunk()) {
125 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
126 ++num_chunks;
127 }
176 128
177 const auto input_config = MakeStreamConfig(&in_file); 129 if (FLAGS_perf) {
178 const auto output_config = MakeStreamConfig(&out_file); 130 const auto& proc_time = processor->proc_time();
179 const auto reverse_input_config = MakeStreamConfig(in_rev_file.get()); 131 int64_t exec_time_us = proc_time.sum.Microseconds();
180 const auto reverse_output_config = MakeStreamConfig(out_rev_file.get()); 132 printf(
133 "\nExecution time: %.3f s, File time: %.2f s\n"
134 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
135 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
136 exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
137 1.f * proc_time.min.Microseconds());
138 }
181 139
182 while (in_file.ReadSamples(in_interleaved.size(),
183 &in_interleaved[0]) == in_interleaved.size()) {
184 // Have logs display the file time rather than wallclock time.
185 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
186 FloatS16ToFloat(&in_interleaved[0], in_interleaved.size(),
187 &in_interleaved[0]);
188 Deinterleave(&in_interleaved[0], in_buf.num_frames(),
189 in_buf.num_channels(), in_buf.channels());
190 if (process_reverse) {
191 in_rev_file->ReadSamples(in_rev_interleaved.size(),
192 in_rev_interleaved.data());
193 FloatS16ToFloat(in_rev_interleaved.data(), in_rev_interleaved.size(),
194 in_rev_interleaved.data());
195 Deinterleave(in_rev_interleaved.data(), in_rev_buf->num_frames(),
196 in_rev_buf->num_channels(), in_rev_buf->channels());
197 }
198
199 if (FLAGS_perf) {
200 processing_start_time = TickTime::Now();
201 }
202 RTC_CHECK_EQ(kNoErr, ap->ProcessStream(in_buf.channels(), input_config,
203 output_config, out_buf.channels()));
204 if (process_reverse) {
205 RTC_CHECK_EQ(kNoErr, ap->ProcessReverseStream(
206 in_rev_buf->channels(), reverse_input_config,
207 reverse_output_config, out_rev_buf->channels()));
208 }
209 if (FLAGS_perf) {
210 accumulated_time += TickTime::Now() - processing_start_time;
211 }
212
213 Interleave(out_buf.channels(), out_buf.num_frames(),
214 out_buf.num_channels(), &out_interleaved[0]);
215 FloatToFloatS16(&out_interleaved[0], out_interleaved.size(),
216 &out_interleaved[0]);
217 out_file.WriteSamples(&out_interleaved[0], out_interleaved.size());
218 if (process_reverse) {
219 Interleave(out_rev_buf->channels(), out_rev_buf->num_frames(),
220 out_rev_buf->num_channels(), out_rev_interleaved.data());
221 FloatToFloatS16(out_rev_interleaved.data(), out_rev_interleaved.size(),
222 out_rev_interleaved.data());
223 out_rev_file->WriteSamples(out_rev_interleaved.data(),
224 out_rev_interleaved.size());
225 }
226 num_chunks++;
227 }
228 if (FLAGS_perf) {
229 int64_t execution_time_ms = accumulated_time.Milliseconds();
230 printf("\nExecution time: %.3f s\nFile time: %.2f s\n"
231 "Time per chunk: %.3f ms\n",
232 execution_time_ms * 0.001f, num_chunks * 1.f / kChunksPerSecond,
233 execution_time_ms * 1.f / num_chunks);
234 }
235 return 0; 140 return 0;
236 } 141 }
237 142
238 } // namespace webrtc 143 } // namespace webrtc
239 144
240 int main(int argc, char* argv[]) { 145 int main(int argc, char* argv[]) {
241 return webrtc::main(argc, argv); 146 return webrtc::main(argc, argv);
242 } 147 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698