blob: 381d7fd2b6750886974771e6a172aa70088d1335 [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>
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000012#include <sstream>
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000013#include <string>
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000014
15#include "gflags/gflags.h"
16#include "webrtc/base/checks.h"
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000017#include "webrtc/base/scoped_ptr.h"
kjellander@webrtc.org035e9122015-01-28 19:57:00 +000018#include "webrtc/common_audio/channel_buffer.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000019#include "webrtc/common_audio/wav_file.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000020#include "webrtc/modules/audio_processing/include/audio_processing.h"
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070021#include "webrtc/modules/audio_processing/test/protobuf_utils.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000022#include "webrtc/modules/audio_processing/test/test_utils.h"
Alejandro Luebs5d22c002015-04-15 11:26:40 -070023#include "webrtc/system_wrappers/interface/tick_util.h"
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -070024#include "webrtc/test/testsupport/trace_to_stderr.h"
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000025
26DEFINE_string(dump, "", "The name of the debug dump file to read from.");
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070027DEFINE_string(i, "", "The name of the input file to read from.");
28DEFINE_string(o, "out.wav", "Name of the output file to write to.");
29DEFINE_int32(out_channels, 0, "Number of output channels. Defaults to input.");
30DEFINE_int32(out_sample_rate, 0,
31 "Output sample rate in Hz. Defaults to input.");
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000032DEFINE_string(mic_positions, "",
33 "Space delimited cartesian coordinates of microphones in meters. "
34 "The coordinates of each point are contiguous. "
35 "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000036
37DEFINE_bool(aec, false, "Enable echo cancellation.");
38DEFINE_bool(agc, false, "Enable automatic gain control.");
39DEFINE_bool(hpf, false, "Enable high-pass filtering.");
40DEFINE_bool(ns, false, "Enable noise suppression.");
41DEFINE_bool(ts, false, "Enable transient suppression.");
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000042DEFINE_bool(bf, false, "Enable beamforming.");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000043DEFINE_bool(all, false, "Enable all components.");
44
45DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3].");
46
Alejandro Luebs5d22c002015-04-15 11:26:40 -070047DEFINE_bool(perf, false, "Enable performance tests.");
48
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070049namespace webrtc {
50namespace {
51
52const int kChunksPerSecond = 100;
53const char kUsage[] =
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000054 "Command-line tool to run audio processing on WAV files. Accepts either\n"
55 "an input capture WAV file or protobuf debug dump and writes to an output\n"
56 "WAV file.\n"
57 "\n"
58 "All components are disabled by default. If any bi-directional components\n"
59 "are enabled, only debug dump files are permitted.";
60
mgraczyk@chromium.org4ddde2e2015-01-29 22:39:44 +000061} // namespace
62
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000063int main(int argc, char* argv[]) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070064 google::SetUsageMessage(kUsage);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000065 google::ParseCommandLineFlags(&argc, &argv, true);
66
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070067 if (!((FLAGS_i == "") ^ (FLAGS_dump == ""))) {
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000068 fprintf(stderr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070069 "An input file must be specified with either -i or -dump.\n");
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000070 return 1;
71 }
72 if (FLAGS_dump != "") {
73 fprintf(stderr, "FIXME: the -dump option is not yet implemented.\n");
74 return 1;
75 }
76
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -070077 test::TraceToStderr trace_to_stderr(true);
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070078 WavReader in_file(FLAGS_i);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000079 // If the output format is uninitialized, use the input format.
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070080 const int out_channels =
81 FLAGS_out_channels ? FLAGS_out_channels : in_file.num_channels();
82 const int out_sample_rate =
83 FLAGS_out_sample_rate ? FLAGS_out_sample_rate : in_file.sample_rate();
84 WavWriter out_file(FLAGS_o, out_sample_rate, out_channels);
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000085
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000086 Config config;
87 config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000088
89 if (FLAGS_bf || FLAGS_all) {
Andrew MacDonaldcb05b722015-05-07 22:17:51 -070090 const size_t num_mics = in_file.num_channels();
91 const std::vector<Point> array_geometry =
92 ParseArrayGeometry(FLAGS_mic_positions, num_mics);
93 CHECK_EQ(array_geometry.size(), num_mics);
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +000094
95 config.Set<Beamforming>(new Beamforming(true, array_geometry));
96 }
97
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000098 rtc::scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config));
andrew@webrtc.org08df9b22014-12-16 20:57:15 +000099 if (FLAGS_dump != "") {
100 CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all));
101 } else if (FLAGS_aec) {
102 fprintf(stderr, "-aec requires a -dump file.\n");
103 return -1;
104 }
105 CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all));
106 CHECK_EQ(kNoErr, ap->gain_control()->set_mode(GainControl::kFixedDigital));
107 CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all));
108 CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all));
109 if (FLAGS_ns_level != -1)
110 CHECK_EQ(kNoErr, ap->noise_suppression()->set_level(
111 static_cast<NoiseSuppression::Level>(FLAGS_ns_level)));
112
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +0000113 printf("Input file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700114 FLAGS_i.c_str(), in_file.num_channels(), in_file.sample_rate());
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +0000115 printf("Output file: %s\nChannels: %d, Sample rate: %d Hz\n\n",
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700116 FLAGS_o.c_str(), out_file.num_channels(), out_file.sample_rate());
mgraczyk@chromium.org5a92b782015-01-15 01:28:36 +0000117
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700118 ChannelBuffer<float> in_buf(
119 rtc::CheckedDivExact(in_file.sample_rate(), kChunksPerSecond),
120 in_file.num_channels());
121 ChannelBuffer<float> out_buf(
122 rtc::CheckedDivExact(out_file.sample_rate(), kChunksPerSecond),
123 out_file.num_channels());
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000124
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700125 std::vector<float> in_interleaved(in_buf.size());
126 std::vector<float> out_interleaved(out_buf.size());
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700127 TickTime processing_start_time;
128 TickInterval accumulated_time;
129 int num_chunks = 0;
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700130 while (in_file.ReadSamples(in_interleaved.size(),
131 &in_interleaved[0]) == in_interleaved.size()) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700132 // Have logs display the file time rather than wallclock time.
133 trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond);
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700134 FloatS16ToFloat(&in_interleaved[0], in_interleaved.size(),
135 &in_interleaved[0]);
136 Deinterleave(&in_interleaved[0], in_buf.num_frames(),
137 in_buf.num_channels(), in_buf.channels());
138
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700139 if (FLAGS_perf) {
140 processing_start_time = TickTime::Now();
141 }
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000142 CHECK_EQ(kNoErr,
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700143 ap->ProcessStream(in_buf.channels(),
144 in_buf.num_frames(),
145 in_file.sample_rate(),
146 LayoutFromChannels(in_buf.num_channels()),
147 out_file.sample_rate(),
148 LayoutFromChannels(out_buf.num_channels()),
149 out_buf.channels()));
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700150 if (FLAGS_perf) {
151 accumulated_time += TickTime::Now() - processing_start_time;
152 }
Andrew MacDonaldcb05b722015-05-07 22:17:51 -0700153
154 Interleave(out_buf.channels(), out_buf.num_frames(),
155 out_buf.num_channels(), &out_interleaved[0]);
156 FloatToFloatS16(&out_interleaved[0], out_interleaved.size(),
157 &out_interleaved[0]);
158 out_file.WriteSamples(&out_interleaved[0], out_interleaved.size());
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700159 num_chunks++;
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000160 }
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700161 if (FLAGS_perf) {
Andrew MacDonaldb444b3f2015-05-27 17:26:03 -0700162 int64_t execution_time_ms = accumulated_time.Milliseconds();
163 printf("\nExecution time: %.3f s\nFile time: %.2f s\n"
164 "Time per chunk: %.3f ms\n",
165 execution_time_ms * 0.001f, num_chunks * 1.f / kChunksPerSecond,
166 execution_time_ms * 1.f / num_chunks);
Alejandro Luebs5d22c002015-04-15 11:26:40 -0700167 }
andrew@webrtc.org08df9b22014-12-16 20:57:15 +0000168 return 0;
169}
170
171} // namespace webrtc
172
173int main(int argc, char* argv[]) {
174 return webrtc::main(argc, argv);
175}