blob: 33790d837f417768efdba9ba0d36a03ee5bd075f [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"
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.");
Alejandro Luebsaf2f3dd2016-03-29 14:54:37 -070044DEFINE_string(ri, "", "Name of the render input stream file to read from.");
45DEFINE_string(
46 ro,
47 "out_reverse.wav",
48 "Name of the output file to write the processed render stream to.");
aluebsb0ad43b2015-11-20 00:11:53 -080049DEFINE_int32(out_channels, 1, "Number of output channels.");
Peter Kasting69558702016-01-12 16:26:35 -080050const bool out_channels_dummy =
51 google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels);
Alejandro Luebsaf2f3dd2016-03-29 14:54:37 -070052DEFINE_int32(rev_out_channels, 1, "Number of reverse output channels.");
53const bool rev_out_channels_dummy =
54 google::RegisterFlagValidator(&FLAGS_rev_out_channels,
55 &ValidateOutChannels);
aluebsb0ad43b2015-11-20 00:11:53 -080056DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz.");
Alejandro Luebsaf2f3dd2016-03-29 14:54:37 -070057DEFINE_int32(rev_out_sample_rate, 48000, "Reverse output sample rate in Hz.");
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000058DEFINE_string(mic_positions, "",
59 "Space delimited cartesian coordinates of microphones in meters. "
60 "The coordinates of each point are contiguous. "
61 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
aluebsb0ad43b2015-11-20 00:11:53 -080062DEFINE_double(
63 target_angle_degrees,
64 90,
65 "The azimuth of the target in degrees. Only applies to beamforming.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000066
67DEFINE_bool(aec, false, "Enable echo cancellation.");
68DEFINE_bool(agc, false, "Enable automatic gain control.");
69DEFINE_bool(hpf, false, "Enable high-pass filtering.");
70DEFINE_bool(ns, false, "Enable noise suppression.");
71DEFINE_bool(ts, false, "Enable transient suppression.");
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000072DEFINE_bool(bf, false, "Enable beamforming.");
ekmeyerson60d9b332015-08-14 10:35:55 -070073DEFINE_bool(ie, false, "Enable intelligibility enhancer.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000074DEFINE_bool(all, false, "Enable all components.");
75
76DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
77
Alejandro Luebs5d22c002015-04-15 11:26:40 -070078DEFINE_bool(perf, false, "Enable performance tests.");
79
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070080namespace webrtc {
81namespace {
82
83const int kChunksPerSecond = 100;
84const char kUsage[] =
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000085 "Command-line tool to run audio processing on WAV files. Accepts either\n"
86 "an input capture WAV file or protobuf debug dump and writes to an output\n"
87 "WAV file.\n"
88 "\n"
Alejandro Luebsaf2f3dd2016-03-29 14:54:37 -070089 "All components are disabled by default.";
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000090
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000091} // namespace
92
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000093int main(int argc, char* argv[]) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070094 google::SetUsageMessage(kUsage);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000095 google::ParseCommandLineFlags(&argc, &argv, true);
96
pbosbb36fdf2015-07-09 07:48:14 -070097 if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) {
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000098 fprintf(stderr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070099 "An input file must be specified with either -i or -dump.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000100 return 1;
101 }
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000102
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
kwiberg62eaacf2016-02-17 06:39:05 -0800118 std::unique_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
kwiberg62eaacf2016-02-17 06:39:05 -0800130 std::unique_ptr<AudioFileProcessor> processor;
131 auto out_file = std::unique_ptr<WavWriter>(new WavWriter(
Peter Kasting69558702016-01-12 16:26:35 -0800132 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()) {
kwiberg62eaacf2016-02-17 06:39:05 -0800135 auto in_file = std::unique_ptr<WavReader>(new WavReader(FLAGS_i));
aluebsb0ad43b2015-11-20 00:11:53 -0800136 std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl;
Alejandro Luebsaf2f3dd2016-03-29 14:54:37 -0700137 std::unique_ptr<WavReader> reverse_in_file;
138 std::unique_ptr<WavWriter> reverse_out_file;
139 if (!FLAGS_ri.empty()) {
140 reverse_in_file.reset(new WavReader(FLAGS_ri));
141 reverse_out_file.reset(new WavWriter(
142 FLAGS_ro,
143 FLAGS_rev_out_sample_rate,
144 static_cast<size_t>(FLAGS_rev_out_channels)));
145 std::cout << FLAGS_ri << ": "
146 << reverse_in_file->FormatAsString() << std::endl;
147 std::cout << FLAGS_ro << ": "
148 << reverse_out_file->FormatAsString() << std::endl;
149 }
150 processor.reset(new WavFileProcessor(std::move(ap),
151 std::move(in_file),
152 std::move(out_file),
153 std::move(reverse_in_file),
154 std::move(reverse_out_file)));
andrewbdafe312015-10-29 23:42:54 -0700155
aluebsb0ad43b2015-11-20 00:11:53 -0800156 } else {
157 processor.reset(new AecDumpFileProcessor(
kwiberg0eb15ed2015-12-17 03:04:15 -0800158 std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file)));
andrewbdafe312015-10-29 23:42:54 -0700159 }
160
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700161 int num_chunks = 0;
aluebsb0ad43b2015-11-20 00:11:53 -0800162 while (processor->ProcessChunk()) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700163 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
aluebsb0ad43b2015-11-20 00:11:53 -0800164 ++num_chunks;
kjellanderb7a5c162015-11-05 12:33:18 -0800165 }
aluebsb0ad43b2015-11-20 00:11:53 -0800166
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700167 if (FLAGS_perf) {
aluebsb0ad43b2015-11-20 00:11:53 -0800168 const auto& proc_time = processor->proc_time();
Niels Möllerd28db7f2016-05-10 16:31:47 +0200169 int64_t exec_time_us = proc_time.sum / rtc::kNumNanosecsPerMicrosec;
aluebsb0ad43b2015-11-20 00:11:53 -0800170 printf(
171 "\nExecution time: %.3f s, File time: %.2f s\n"
172 "Time per chunk (mean, max, min):\n%.0f us, %.0f us, %.0f us\n",
173 exec_time_us * 1e-6, num_chunks * 1.f / kChunksPerSecond,
Niels Möllerd28db7f2016-05-10 16:31:47 +0200174 exec_time_us * 1.f / num_chunks,
175 1.f * proc_time.max / rtc::kNumNanosecsPerMicrosec,
176 1.f * proc_time.min / rtc::kNumNanosecsPerMicrosec);
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}