blob: 41e45bfdc69c5c20525d89a0df3dc771fb70004d [file] [log] [blame]
andrew@webrtc.org08df9b22014-12-16 20:57:15 +00001/*
2 * Copyright (c) 2014 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 <stdio.h>
kwiberg62eaacf2016-02-17 06:39:05 -080012
aluebsb0ad43b2015-11-20 00:11:53 -080013#include <iostream>
kwiberg62eaacf2016-02-17 06:39:05 -080014#include <memory>
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000015#include <sstream>
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000016#include <string>
kwiberg0eb15ed2015-12-17 03:04:15 -080017#include <utility>
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000018
19#include "gflags/gflags.h"
20#include "webrtc/base/checks.h"
Peter Kasting69558702016-01-12 16:26:35 -080021#include "webrtc/base/format_macros.h"
kjellander@webrtc.org035e9122015-01-28 19:57:00 +000022#include "webrtc/common_audio/channel_buffer.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000023#include "webrtc/common_audio/wav_file.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000024#include "webrtc/modules/audio_processing/include/audio_processing.h"
aluebsb0ad43b2015-11-20 00:11:53 -080025#include "webrtc/modules/audio_processing/test/audio_file_processor.h"
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070026#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000027#include "webrtc/modules/audio_processing/test/test_utils.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010028#include "webrtc/system_wrappers/include/tick_util.h"
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -070029#include "webrtc/test/testsupport/trace_to_stderr.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000030
Peter Kasting69558702016-01-12 16:26:35 -080031namespace {
32
33bool ValidateOutChannels(const char* flagname, int32_t value) {
34 return value >= 0;
35}
36
37} // namespace
38
aluebsb0ad43b2015-11-20 00:11:53 -080039DEFINE_string(dump, "", "Name of the aecdump debug file to read from.");
40DEFINE_string(i, "", "Name of the capture input stream file to read from.");
41DEFINE_string(
42 o,
43 "out.wav",
44 "Name of the output file to write the processed capture stream to.");
Alejandro Luebs98c69a02016-03-29 12:43:32 -070045DEFINE_string(ri, "", "Name of the render input stream file to read from.");
46DEFINE_string(
47 ro,
48 "out_reverse.wav",
49 "Name of the output file to write the processed render stream to.");
aluebsb0ad43b2015-11-20 00:11:53 -080050DEFINE_int32(out_channels, 1, "Number of output channels.");
Peter Kasting69558702016-01-12 16:26:35 -080051const bool out_channels_dummy =
52 google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels);
Alejandro Luebs98c69a02016-03-29 12:43:32 -070053DEFINE_int32(rev_out_channels, 1, "Number of reverse output channels.");
54const bool rev_out_channels_dummy =
55 google::RegisterFlagValidator(&FLAGS_rev_out_channels,
56 &ValidateOutChannels);
aluebsb0ad43b2015-11-20 00:11:53 -080057DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
Alejandro Luebs98c69a02016-03-29 12:43:32 -070058DEFINE_int32(rev_out_sample_rate, 48000, "Reverse output sample rate in Hz.");
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000059DEFINE_string(mic_positions, "",
60 "Space delimited cartesian coordinates of microphones in meters. "
61 "The coordinates of each point are contiguous. "
62 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
aluebsb0ad43b2015-11-20 00:11:53 -080063DEFINE_double(
64 target_angle_degrees,
65 90,
66 "The azimuth of the target in degrees. Only applies to beamforming.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000067
68DEFINE_bool(aec, false, "Enable echo cancellation.");
69DEFINE_bool(agc, false, "Enable automatic gain control.");
70DEFINE_bool(hpf, false, "Enable high-pass filtering.");
71DEFINE_bool(ns, false, "Enable noise suppression.");
72DEFINE_bool(ts, false, "Enable transient suppression.");
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000073DEFINE_bool(bf, false, "Enable beamforming.");
ekmeyerson60d9b332015-08-14 10:35:55 -070074DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000075DEFINE_bool(all, false, "Enable all components.");
76
77DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
78
Alejandro Luebs5d22c002015-04-15 11:26:40 -070079DEFINE_bool(perf, false, "Enable performance tests.");
80
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070081namespace webrtc {
82namespace {
83
84const int kChunksPerSecond = 100;
85const char kUsage[] =
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000086 "Command-line tool to run audio processing on WAV files. Accepts either\n"
87 "an input capture WAV file or protobuf debug dump and writes to an output\n"
88 "WAV file.\n"
89 "\n"
Alejandro Luebs98c69a02016-03-29 12:43:32 -070090 "All components are disabled by default.";
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000091
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000092} // namespace
93
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000094int main(int argc, char* argv[]) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070095 google::SetUsageMessage(kUsage);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000096 google::ParseCommandLineFlags(&argc, &argv, true);
97
pbosbb36fdf2015-07-09 07:48:14 -070098 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000099 fprintf(stderr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700100 "An input file must be specified with either -i or -dump.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000101 return 1;
102 }
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000103
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700104 test::TraceToStderr trace_to_stderr(true);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000105 Config config;
kjellanderb7a5c162015-11-05 12:33:18 -0800106 if (FLAGS_bf || FLAGS_all) {
aluebsb0ad43b2015-11-20 00:11:53 -0800107 if (FLAGS_mic_positions.empty()) {
108 fprintf(stderr, "-mic_positions must be specified when -bf is used.\n");
109 return 1;
110 }
kjellanderb7a5c162015-11-05 12:33:18 -0800111 config.Set<Beamforming>(new Beamforming(
aluebsb0ad43b2015-11-20 00:11:53 -0800112 true, ParseArrayGeometry(FLAGS_mic_positions),
kjellanderb7a5c162015-11-05 12:33:18 -0800113 SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f,
114 1.f)));
115 }
aluebsb0ad43b2015-11-20 00:11:53 -0800116 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
117 config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all));
kjellanderb7a5c162015-11-05 12:33:18 -0800118
kwiberg62eaacf2016-02-17 06:39:05 -0800119 std::unique_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
aluebsb0ad43b2015-11-20 00:11:53 -0800120 RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
henrikg91d6ede2015-09-17 00:24:34 -0700121 RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
henrikg91d6ede2015-09-17 00:24:34 -0700122 RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
123 RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
kjellander86b40502015-11-05 06:23:02 -0800124 if (FLAGS_ns_level != -1) {
henrikg91d6ede2015-09-17 00:24:34 -0700125 RTC_CHECK_EQ(kNoErr,
126 ap->noise_suppression()->set_level(
127 static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
ekmeyerson60d9b332015-08-14 10:35:55 -0700128 }
aluebs8e1809f2015-10-30 15:29:17 -0700129 ap->set_stream_key_pressed(FLAGS_ts);
ekmeyerson60d9b332015-08-14 10:35:55 -0700130
kwiberg62eaacf2016-02-17 06:39:05 -0800131 std::unique_ptr<AudioFileProcessor> processor;
132 auto out_file = std::unique_ptr<WavWriter>(new WavWriter(
Peter Kasting69558702016-01-12 16:26:35 -0800133 FLAGS_o, FLAGS_out_sample_rate, static_cast<size_t>(FLAGS_out_channels)));
aluebsb0ad43b2015-11-20 00:11:53 -0800134 std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl;
135 if (FLAGS_dump.empty()) {
kwiberg62eaacf2016-02-17 06:39:05 -0800136 auto in_file = std::unique_ptr<WavReader>(new WavReader(FLAGS_i));
aluebsb0ad43b2015-11-20 00:11:53 -0800137 std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl;
Alejandro Luebs98c69a02016-03-29 12:43:32 -0700138 std::unique_ptr<WavReader> reverse_in_file;
139 std::unique_ptr<WavWriter> reverse_out_file;
140 if (!FLAGS_ri.empty()) {
141 reverse_in_file.reset(new WavReader(FLAGS_ri));
142 reverse_out_file.reset(new WavWriter(
143 FLAGS_ro,
144 FLAGS_rev_out_sample_rate,
145 static_cast<size_t>(FLAGS_rev_out_channels)));
146 std::cout << FLAGS_ri << ": "
147 << reverse_in_file->FormatAsString() << std::endl;
148 std::cout << FLAGS_ro << ": "
149 << reverse_out_file->FormatAsString() << std::endl;
150 }
151 processor.reset(new WavFileProcessor(std::move(ap),
152 std::move(in_file),
153 std::move(out_file),
154 std::move(reverse_in_file),
155 std::move(reverse_out_file)));
andrewbdafe312015-10-29 23:42:54 -0700156
aluebsb0ad43b2015-11-20 00:11:53 -0800157 } else {
158 processor.reset(new AecDumpFileProcessor(
kwiberg0eb15ed2015-12-17 03:04:15 -0800159 std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700160 }
161
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700162 int num_chunks = 0;
aluebsb0ad43b2015-11-20 00:11:53 -0800163 while (processor->ProcessChunk()) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700164 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
aluebsb0ad43b2015-11-20 00:11:53 -0800165 ++num_chunks;
kjellanderb7a5c162015-11-05 12:33:18 -0800166 }
aluebsb0ad43b2015-11-20 00:11:53 -0800167
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700168 if (FLAGS_perf) {
aluebsb0ad43b2015-11-20 00:11:53 -0800169 const auto& proc_time = processor->proc_time();
170 int64_t exec_time_us = proc_time.sum.Microseconds();
171 printf(
172 "\nExecution time: %.3f s, File time: %.2f s\n"
173 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
174 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
175 exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
176 1.f * proc_time.min.Microseconds());
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700177 }
aluebsb0ad43b2015-11-20 00:11:53 -0800178
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000179 return 0;
180}
181
182} // namespace webrtc
183
184int main(int argc, char* argv[]) {
185 return webrtc::main(argc, argv);
186}