andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 1 | /* |
| 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> |
kwiberg | 62eaacf | 2016-02-17 06:39:05 -0800 | [diff] [blame] | 12 | |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 13 | #include <iostream> |
kwiberg | 62eaacf | 2016-02-17 06:39:05 -0800 | [diff] [blame] | 14 | #include <memory> |
mgraczyk@chromium.org | 4ddde2e | 2015-01-29 22:39:44 +0000 | [diff] [blame] | 15 | #include <sstream> |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 16 | #include <string> |
kwiberg | 0eb15ed | 2015-12-17 03:04:15 -0800 | [diff] [blame] | 17 | #include <utility> |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 18 | |
| 19 | #include "gflags/gflags.h" |
| 20 | #include "webrtc/base/checks.h" |
Peter Kasting | 6955870 | 2016-01-12 16:26:35 -0800 | [diff] [blame] | 21 | #include "webrtc/base/format_macros.h" |
kjellander@webrtc.org | 035e912 | 2015-01-28 19:57:00 +0000 | [diff] [blame] | 22 | #include "webrtc/common_audio/channel_buffer.h" |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 23 | #include "webrtc/common_audio/wav_file.h" |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 24 | #include "webrtc/modules/audio_processing/include/audio_processing.h" |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 25 | #include "webrtc/modules/audio_processing/test/audio_file_processor.h" |
Andrew MacDonald | cb05b72 | 2015-05-07 22:17:51 -0700 | [diff] [blame] | 26 | #include "webrtc/modules/audio_processing/test/protobuf_utils.h" |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 27 | #include "webrtc/modules/audio_processing/test/test_utils.h" |
Henrik Kjellander | 98f5351 | 2015-10-28 18:17:40 +0100 | [diff] [blame] | 28 | #include "webrtc/system_wrappers/include/tick_util.h" |
Andrew MacDonald | b444b3f | 2015-05-27 17:26:03 -0700 | [diff] [blame] | 29 | #include "webrtc/test/testsupport/trace_to_stderr.h" |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 30 | |
Peter Kasting | 6955870 | 2016-01-12 16:26:35 -0800 | [diff] [blame] | 31 | namespace { |
| 32 | |
| 33 | bool ValidateOutChannels(const char* flagname, int32_t value) { |
| 34 | return value >= 0; |
| 35 | } |
| 36 | |
| 37 | } // namespace |
| 38 | |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 39 | DEFINE_string(dump, "", "Name of the aecdump debug file to read from."); |
| 40 | DEFINE_string(i, "", "Name of the capture input stream file to read from."); |
| 41 | DEFINE_string( |
| 42 | o, |
| 43 | "out.wav", |
| 44 | "Name of the output file to write the processed capture stream to."); |
Alejandro Luebs | 98c69a0 | 2016-03-29 12:43:32 -0700 | [diff] [blame^] | 45 | DEFINE_string(ri, "", "Name of the render input stream file to read from."); |
| 46 | DEFINE_string( |
| 47 | ro, |
| 48 | "out_reverse.wav", |
| 49 | "Name of the output file to write the processed render stream to."); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 50 | DEFINE_int32(out_channels, 1, "Number of output channels."); |
Peter Kasting | 6955870 | 2016-01-12 16:26:35 -0800 | [diff] [blame] | 51 | const bool out_channels_dummy = |
| 52 | google::RegisterFlagValidator(&FLAGS_out_channels, &ValidateOutChannels); |
Alejandro Luebs | 98c69a0 | 2016-03-29 12:43:32 -0700 | [diff] [blame^] | 53 | DEFINE_int32(rev_out_channels, 1, "Number of reverse output channels."); |
| 54 | const bool rev_out_channels_dummy = |
| 55 | google::RegisterFlagValidator(&FLAGS_rev_out_channels, |
| 56 | &ValidateOutChannels); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 57 | DEFINE_int32(out_sample_rate, 48000, "Output sample rate in Hz."); |
Alejandro Luebs | 98c69a0 | 2016-03-29 12:43:32 -0700 | [diff] [blame^] | 58 | DEFINE_int32(rev_out_sample_rate, 48000, "Reverse output sample rate in Hz."); |
mgraczyk@chromium.org | 4ddde2e | 2015-01-29 22:39:44 +0000 | [diff] [blame] | 59 | DEFINE_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\""); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 63 | DEFINE_double( |
| 64 | target_angle_degrees, |
| 65 | 90, |
| 66 | "The azimuth of the target in degrees. Only applies to beamforming."); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 67 | |
| 68 | DEFINE_bool(aec, false, "Enable echo cancellation."); |
| 69 | DEFINE_bool(agc, false, "Enable automatic gain control."); |
| 70 | DEFINE_bool(hpf, false, "Enable high-pass filtering."); |
| 71 | DEFINE_bool(ns, false, "Enable noise suppression."); |
| 72 | DEFINE_bool(ts, false, "Enable transient suppression."); |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 73 | DEFINE_bool(bf, false, "Enable beamforming."); |
ekmeyerson | 60d9b33 | 2015-08-14 10:35:55 -0700 | [diff] [blame] | 74 | DEFINE_bool(ie, false, "Enable intelligibility enhancer."); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 75 | DEFINE_bool(all, false, "Enable all components."); |
| 76 | |
| 77 | DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3]."); |
| 78 | |
Alejandro Luebs | 5d22c00 | 2015-04-15 11:26:40 -0700 | [diff] [blame] | 79 | DEFINE_bool(perf, false, "Enable performance tests."); |
| 80 | |
Andrew MacDonald | cb05b72 | 2015-05-07 22:17:51 -0700 | [diff] [blame] | 81 | namespace webrtc { |
| 82 | namespace { |
| 83 | |
| 84 | const int kChunksPerSecond = 100; |
| 85 | const char kUsage[] = |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 86 | "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 Luebs | 98c69a0 | 2016-03-29 12:43:32 -0700 | [diff] [blame^] | 90 | "All components are disabled by default."; |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 91 | |
mgraczyk@chromium.org | 4ddde2e | 2015-01-29 22:39:44 +0000 | [diff] [blame] | 92 | } // namespace |
| 93 | |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 94 | int main(int argc, char* argv[]) { |
Andrew MacDonald | cb05b72 | 2015-05-07 22:17:51 -0700 | [diff] [blame] | 95 | google::SetUsageMessage(kUsage); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 96 | google::ParseCommandLineFlags(&argc, &argv, true); |
| 97 | |
pbos | bb36fdf | 2015-07-09 07:48:14 -0700 | [diff] [blame] | 98 | if (!((FLAGS_i.empty()) ^ (FLAGS_dump.empty()))) { |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 99 | fprintf(stderr, |
Andrew MacDonald | cb05b72 | 2015-05-07 22:17:51 -0700 | [diff] [blame] | 100 | "An input file must be specified with either -i or -dump.\n"); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 101 | return 1; |
| 102 | } |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 103 | |
Andrew MacDonald | b444b3f | 2015-05-27 17:26:03 -0700 | [diff] [blame] | 104 | test::TraceToStderr trace_to_stderr(true); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 105 | Config config; |
kjellander | b7a5c16 | 2015-11-05 12:33:18 -0800 | [diff] [blame] | 106 | if (FLAGS_bf || FLAGS_all) { |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 107 | if (FLAGS_mic_positions.empty()) { |
| 108 | fprintf(stderr, "-mic_positions must be specified when -bf is used.\n"); |
| 109 | return 1; |
| 110 | } |
kjellander | b7a5c16 | 2015-11-05 12:33:18 -0800 | [diff] [blame] | 111 | config.Set<Beamforming>(new Beamforming( |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 112 | true, ParseArrayGeometry(FLAGS_mic_positions), |
kjellander | b7a5c16 | 2015-11-05 12:33:18 -0800 | [diff] [blame] | 113 | SphericalPointf(DegreesToRadians(FLAGS_target_angle_degrees), 0.f, |
| 114 | 1.f))); |
| 115 | } |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 116 | config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all)); |
| 117 | config.Set<Intelligibility>(new Intelligibility(FLAGS_ie || FLAGS_all)); |
kjellander | b7a5c16 | 2015-11-05 12:33:18 -0800 | [diff] [blame] | 118 | |
kwiberg | 62eaacf | 2016-02-17 06:39:05 -0800 | [diff] [blame] | 119 | std::unique_ptr<AudioProcessing> ap(AudioProcessing::Create(config)); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 120 | RTC_CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all)); |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 121 | RTC_CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all)); |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 122 | 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)); |
kjellander | 86b4050 | 2015-11-05 06:23:02 -0800 | [diff] [blame] | 124 | if (FLAGS_ns_level != -1) { |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 125 | RTC_CHECK_EQ(kNoErr, |
| 126 | ap->noise_suppression()->set_level( |
| 127 | static_cast<NoiseSuppression::Level>(FLAGS_ns_level))); |
ekmeyerson | 60d9b33 | 2015-08-14 10:35:55 -0700 | [diff] [blame] | 128 | } |
aluebs | 8e1809f | 2015-10-30 15:29:17 -0700 | [diff] [blame] | 129 | ap->set_stream_key_pressed(FLAGS_ts); |
ekmeyerson | 60d9b33 | 2015-08-14 10:35:55 -0700 | [diff] [blame] | 130 | |
kwiberg | 62eaacf | 2016-02-17 06:39:05 -0800 | [diff] [blame] | 131 | std::unique_ptr<AudioFileProcessor> processor; |
| 132 | auto out_file = std::unique_ptr<WavWriter>(new WavWriter( |
Peter Kasting | 6955870 | 2016-01-12 16:26:35 -0800 | [diff] [blame] | 133 | FLAGS_o, FLAGS_out_sample_rate, static_cast<size_t>(FLAGS_out_channels))); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 134 | std::cout << FLAGS_o << ": " << out_file->FormatAsString() << std::endl; |
| 135 | if (FLAGS_dump.empty()) { |
kwiberg | 62eaacf | 2016-02-17 06:39:05 -0800 | [diff] [blame] | 136 | auto in_file = std::unique_ptr<WavReader>(new WavReader(FLAGS_i)); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 137 | std::cout << FLAGS_i << ": " << in_file->FormatAsString() << std::endl; |
Alejandro Luebs | 98c69a0 | 2016-03-29 12:43:32 -0700 | [diff] [blame^] | 138 | 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))); |
andrew | bdafe31 | 2015-10-29 23:42:54 -0700 | [diff] [blame] | 156 | |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 157 | } else { |
| 158 | processor.reset(new AecDumpFileProcessor( |
kwiberg | 0eb15ed | 2015-12-17 03:04:15 -0800 | [diff] [blame] | 159 | std::move(ap), fopen(FLAGS_dump.c_str(), "rb"), std::move(out_file))); |
andrew | bdafe31 | 2015-10-29 23:42:54 -0700 | [diff] [blame] | 160 | } |
| 161 | |
Alejandro Luebs | 5d22c00 | 2015-04-15 11:26:40 -0700 | [diff] [blame] | 162 | int num_chunks = 0; |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 163 | while (processor->ProcessChunk()) { |
Andrew MacDonald | b444b3f | 2015-05-27 17:26:03 -0700 | [diff] [blame] | 164 | trace_to_stderr.SetTimeSeconds(num_chunks * 1.f / kChunksPerSecond); |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 165 | ++num_chunks; |
kjellander | b7a5c16 | 2015-11-05 12:33:18 -0800 | [diff] [blame] | 166 | } |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 167 | |
Alejandro Luebs | 5d22c00 | 2015-04-15 11:26:40 -0700 | [diff] [blame] | 168 | if (FLAGS_perf) { |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 169 | 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 Luebs | 5d22c00 | 2015-04-15 11:26:40 -0700 | [diff] [blame] | 177 | } |
aluebs | b0ad43b | 2015-11-20 00:11:53 -0800 | [diff] [blame] | 178 | |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 179 | return 0; |
| 180 | } |
| 181 | |
| 182 | } // namespace webrtc |
| 183 | |
| 184 | int main(int argc, char* argv[]) { |
| 185 | return webrtc::main(argc, argv); |
| 186 | } |