blob: b403c1fe05e1c43b84617d63f09e6419732f29e6 [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.");
45DEFINE_int32(out_channels, 1, "Number of output channels.");
Peter Kasting69558702016-01-12 16:26:35 -080046const bool out_channels_dummy =
47 google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels);
aluebsb0ad43b2015-11-20 00:11:53 -080048DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000049DEFINE_string(mic_positions, "",
50 "Space delimited cartesian coordinates of microphones in meters. "
51 "The coordinates of each point are contiguous. "
52 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
aluebsb0ad43b2015-11-20 00:11:53 -080053DEFINE_double(
54 target_angle_degrees,
55 90,
56 "The azimuth of the target in degrees. Only applies to beamforming.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000057
58DEFINE_bool(aec, false, "Enable echo cancellation.");
59DEFINE_bool(agc, false, "Enable automatic gain control.");
60DEFINE_bool(hpf, false, "Enable high-pass filtering.");
61DEFINE_bool(ns, false, "Enable noise suppression.");
62DEFINE_bool(ts, false, "Enable transient suppression.");
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000063DEFINE_bool(bf, false, "Enable beamforming.");
ekmeyerson60d9b332015-08-14 10:35:55 -070064DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000065DEFINE_bool(all, false, "Enable all components.");
66
67DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
68
Alejandro Luebs5d22c002015-04-15 11:26:40 -070069DEFINE_bool(perf, false, "Enable performance tests.");
70
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070071namespace webrtc {
72namespace {
73
74const int kChunksPerSecond = 100;
75const char kUsage[] =
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000076 "Command-line tool to run audio processing on WAV files. Accepts either\n"
77 "an input capture WAV file or protobuf debug dump and writes to an output\n"
78 "WAV file.\n"
79 "\n"
Alejandro Luebsdd56fa82016-03-29 13:05:40 -070080 "All components are disabled by default. If any bi-directional components\n"
81 "are enabled, only debug dump files are permitted.";
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000082
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000083} // namespace
84
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000085int main(int argc, char* argv[]) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070086 google::SetUsageMessage(kUsage);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000087 google::ParseCommandLineFlags(&argc, &argv, true);
88
pbosbb36fdf2015-07-09 07:48:14 -070089 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000090 fprintf(stderr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070091 "An input file must be specified with either -i or -dump.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000092 return 1;
93 }
Alejandro Luebsdd56fa82016-03-29 13:05:40 -070094 if (FLAGS_dump.empty() && (FLAGS_aec || FLAGS_ie)) {
95 fprintf(stderr, "-aec and -ie require a -dump file.\n");
96 return 1;
97 }
98 if (FLAGS_ie) {
99 fprintf(stderr,
100 "FIXME(ajm): The intelligibility enhancer output is not dumped.\n");
101 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 Luebsdd56fa82016-03-29 13:05:40 -0700138 processor.reset(new WavFileProcessor(std::move(ap), std::move(in_file),
139 std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700140
aluebsb0ad43b2015-11-20 00:11:53 -0800141 } else {
142 processor.reset(new AecDumpFileProcessor(
kwiberg0eb15ed2015-12-17 03:04:15 -0800143 std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700144 }
145
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700146 int num_chunks = 0;
aluebsb0ad43b2015-11-20 00:11:53 -0800147 while (processor->ProcessChunk()) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700148 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
aluebsb0ad43b2015-11-20 00:11:53 -0800149 ++num_chunks;
kjellanderb7a5c162015-11-05 12:33:18 -0800150 }
aluebsb0ad43b2015-11-20 00:11:53 -0800151
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700152 if (FLAGS_perf) {
aluebsb0ad43b2015-11-20 00:11:53 -0800153 const auto& proc_time = processor->proc_time();
154 int64_t exec_time_us = proc_time.sum.Microseconds();
155 printf(
156 "\nExecution time: %.3f s, File time: %.2f s\n"
157 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
158 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
159 exec_time_us * 1.f / num_chunks, 1.f * proc_time.max.Microseconds(),
160 1.f * proc_time.min.Microseconds());
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700161 }
aluebsb0ad43b2015-11-20 00:11:53 -0800162
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000163 return 0;
164}
165
166} // namespace webrtc
167
168int main(int argc, char* argv[]) {
169 return webrtc::main(argc, argv);
170}