blob: a489d255c8af697e5dc3de3cb07cee433cf156b2 [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>
aluebsb0ad43b2015-11-20 00:11:53 -080012#include <iostream>
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000013#include <sstream>
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000014#include <string>
kwiberg0eb15ed2015-12-17 03:04:15 -080015#include <utility>
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000016
17#include "gflags/gflags.h"
18#include "webrtc/base/checks.h"
Peter Kasting69558702016-01-12 16:26:35 -080019#include "webrtc/base/format_macros.h"
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000020#include "webrtc/base/scoped_ptr.h"
kjellander@webrtc.org035e9122015-01-28 19:57:00 +000021#include "webrtc/common_audio/channel_buffer.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000022#include "webrtc/common_audio/wav_file.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000023#include "webrtc/modules/audio_processing/include/audio_processing.h"
aluebsb0ad43b2015-11-20 00:11:53 -080024#include "webrtc/modules/audio_processing/test/audio_file_processor.h"
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070025#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000026#include "webrtc/modules/audio_processing/test/test_utils.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010027#include "webrtc/system_wrappers/include/tick_util.h"
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -070028#include "webrtc/test/testsupport/trace_to_stderr.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000029
Peter Kasting69558702016-01-12 16:26:35 -080030namespace {
31
32bool ValidateOutChannels(const char* flagname, int32_t value) {
33 return value >= 0;
34}
35
36} // namespace
37
aluebsb0ad43b2015-11-20 00:11:53 -080038DEFINE_string(dump, "", "Name of the aecdump debug file to read from.");
39DEFINE_string(i, "", "Name of the capture input stream file to read from.");
40DEFINE_string(
41 o,
42 "out.wav",
43 "Name of the output file to write the processed capture stream to.");
44DEFINE_int32(out_channels, 1, "Number of output channels.");
Peter Kasting69558702016-01-12 16:26:35 -080045const bool out_channels_dummy =
46 google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels);
aluebsb0ad43b2015-11-20 00:11:53 -080047DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000048DEFINE_string(mic_positions, "",
49 "Space delimited cartesian coordinates of microphones in meters. "
50 "The coordinates of each point are contiguous. "
51 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
aluebsb0ad43b2015-11-20 00:11:53 -080052DEFINE_double(
53 target_angle_degrees,
54 90,
55 "The azimuth of the target in degrees. Only applies to beamforming.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000056
57DEFINE_bool(aec, false, "Enable echo cancellation.");
58DEFINE_bool(agc, false, "Enable automatic gain control.");
59DEFINE_bool(hpf, false, "Enable high-pass filtering.");
60DEFINE_bool(ns, false, "Enable noise suppression.");
61DEFINE_bool(ts, false, "Enable transient suppression.");
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000062DEFINE_bool(bf, false, "Enable beamforming.");
ekmeyerson60d9b332015-08-14 10:35:55 -070063DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000064DEFINE_bool(all, false, "Enable all components.");
65
66DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
67
Alejandro Luebs5d22c002015-04-15 11:26:40 -070068DEFINE_bool(perf, false, "Enable performance tests.");
69
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070070namespace webrtc {
71namespace {
72
73const int kChunksPerSecond = 100;
74const char kUsage[] =
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000075 "Command-line tool to run audio processing on WAV files. Accepts either\n"
76 "an input capture WAV file or protobuf debug dump and writes to an output\n"
77 "WAV file.\n"
78 "\n"
79 "All components are disabled by default. If any bi-directional components\n"
80 "are enabled, only debug dump files are permitted.";
81
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000082} // namespace
83
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000084int main(int argc, char* argv[]) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070085 google::SetUsageMessage(kUsage);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000086 google::ParseCommandLineFlags(&argc, &argv, true);
87
pbosbb36fdf2015-07-09 07:48:14 -070088 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000089 fprintf(stderr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070090 "An input file must be specified with either -i or -dump.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000091 return 1;
92 }
aluebsb0ad43b2015-11-20 00:11:53 -080093 if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) {
94 fprintf(stderr, "-aec and -ie require a -dump file.\n");
95 return 1;
96 }
97 if (FLAGS_ie) {
98 fprintf(stderr,
99 "FIXME(ajm): The intelligibility enhancer output is not dumped.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000100 return 1;
101 }
102
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700103 test::TraceToStderr trace_to_stderr(true);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000104 Config config;
kjellanderb7a5c162015-11-05 12:33:18 -0800105 if (FLAGS_bf || FLAGS_all) {
aluebsb0ad43b2015-11-20 00:11:53 -0800106 if (FLAGS_mic_positions.empty()) {
107 fprintf(stderr, "-mic_positions must be specified when -bf is used.\n");
108 return 1;
109 }
kjellanderb7a5c162015-11-05 12:33:18 -0800110 config.Set<Beamforming>(new Beamforming(
aluebsb0ad43b2015-11-20 00:11:53 -0800111 true, ParseArrayGeometry(FLAGS_mic_positions),
kjellanderb7a5c162015-11-05 12:33:18 -0800112 SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f,
113 1.f)));
114 }
aluebsb0ad43b2015-11-20 00:11:53 -0800115 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
116 config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all));
kjellanderb7a5c162015-11-05 12:33:18 -0800117
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000118 rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
aluebsb0ad43b2015-11-20 00:11:53 -0800119 RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
henrikg91d6ede2015-09-17 00:24:34 -0700120 RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
henrikg91d6ede2015-09-17 00:24:34 -0700121 RTC_CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
122 RTC_CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
kjellander86b40502015-11-05 06:23:02 -0800123 if (FLAGS_ns_level != -1) {
henrikg91d6ede2015-09-17 00:24:34 -0700124 RTC_CHECK_EQ(kNoErr,
125 ap->noise_suppression()->set_level(
126 static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
ekmeyerson60d9b332015-08-14 10:35:55 -0700127 }
aluebs8e1809f2015-10-30 15:29:17 -0700128 ap->set_stream_key_pressed(FLAGS_ts);
ekmeyerson60d9b332015-08-14 10:35:55 -0700129
aluebsb0ad43b2015-11-20 00:11:53 -0800130 rtc::scoped_ptr<AudioFileProcessor> processor;
Peter Kasting69558702016-01-12 16:26:35 -0800131 auto out_file = rtc_make_scoped_ptr(new WavWriter(
132 FLAGS_o, FLAGS_out_sample_rate, static_cast<size_t>(FLAGS_out_channels)));
aluebsb0ad43b2015-11-20 00:11:53 -0800133 std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl;
134 if (FLAGS_dump.empty()) {
135 auto in_file = rtc_make_scoped_ptr(new WavReader(FLAGS_i));
136 std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl;
kwiberg0eb15ed2015-12-17 03:04:15 -0800137 processor.reset(new WavFileProcessor(std::move(ap), std::move(in_file),
138 std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700139
aluebsb0ad43b2015-11-20 00:11:53 -0800140 } else {
141 processor.reset(new AecDumpFileProcessor(
kwiberg0eb15ed2015-12-17 03:04:15 -0800142 std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700143 }
144
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700145 int num_chunks = 0;
aluebsb0ad43b2015-11-20 00:11:53 -0800146 while (processor->ProcessChunk()) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700147 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
aluebsb0ad43b2015-11-20 00:11:53 -0800148 ++num_chunks;
kjellanderb7a5c162015-11-05 12:33:18 -0800149 }
aluebsb0ad43b2015-11-20 00:11:53 -0800150
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700151 if (FLAGS_perf) {
aluebsb0ad43b2015-11-20 00:11:53 -0800152 const auto& proc_time = processor->proc_time();
153 int64_t exec_time_us = proc_time.sum.Microseconds();
154 printf(
155 "\nExecution time: %.3f s, File time: %.2f s\n"
156 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
157 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
158 exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
159 1.f * proc_time.min.Microseconds());
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700160 }
aluebsb0ad43b2015-11-20 00:11:53 -0800161
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000162 return 0;
163}
164
165} // namespace webrtc
166
167int main(int argc, char* argv[]) {
168 return webrtc::main(argc, argv);
169}