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> |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 12 | #include <string> |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 13 | |
| 14 | #include "gflags/gflags.h" |
| 15 | #include "webrtc/base/checks.h" |
| 16 | #include "webrtc/common_audio/wav_file.h" |
| 17 | #include "webrtc/modules/audio_processing/channel_buffer.h" |
| 18 | #include "webrtc/modules/audio_processing/include/audio_processing.h" |
| 19 | #include "webrtc/modules/audio_processing/test/test_utils.h" |
| 20 | #include "webrtc/system_wrappers/interface/scoped_ptr.h" |
| 21 | |
| 22 | DEFINE_string(dump, "", "The name of the debug dump file to read from."); |
| 23 | DEFINE_string(c, "", "The name of the capture input file to read from."); |
| 24 | DEFINE_string(o, "out.wav", "Name of the capture output file to write to."); |
| 25 | DEFINE_int32(o_channels, 0, "Number of output channels. Defaults to input."); |
| 26 | DEFINE_int32(o_sample_rate, 0, "Output sample rate in Hz. Defaults to input."); |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 27 | DEFINE_double(mic_spacing, 0.0, |
| 28 | "Microphone spacing in meters. Used when beamforming is enabled"); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 29 | |
| 30 | DEFINE_bool(aec, false, "Enable echo cancellation."); |
| 31 | DEFINE_bool(agc, false, "Enable automatic gain control."); |
| 32 | DEFINE_bool(hpf, false, "Enable high-pass filtering."); |
| 33 | DEFINE_bool(ns, false, "Enable noise suppression."); |
| 34 | DEFINE_bool(ts, false, "Enable transient suppression."); |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 35 | DEFINE_bool(bf, false, "Enable beamforming."); |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 36 | DEFINE_bool(all, false, "Enable all components."); |
| 37 | |
| 38 | DEFINE_int32(ns_level, -1, "Noise suppression level [0 - 3]."); |
| 39 | |
| 40 | static const int kChunksPerSecond = 100; |
| 41 | static const char kUsage[] = |
| 42 | "Command-line tool to run audio processing on WAV files. Accepts either\n" |
| 43 | "an input capture WAV file or protobuf debug dump and writes to an output\n" |
| 44 | "WAV file.\n" |
| 45 | "\n" |
| 46 | "All components are disabled by default. If any bi-directional components\n" |
| 47 | "are enabled, only debug dump files are permitted."; |
| 48 | |
| 49 | namespace webrtc { |
| 50 | |
| 51 | int main(int argc, char* argv[]) { |
| 52 | { |
| 53 | const std::string program_name = argv[0]; |
| 54 | const std::string usage = kUsage; |
| 55 | google::SetUsageMessage(usage); |
| 56 | } |
| 57 | google::ParseCommandLineFlags(&argc, &argv, true); |
| 58 | |
| 59 | if (!((FLAGS_c == "") ^ (FLAGS_dump == ""))) { |
| 60 | fprintf(stderr, |
| 61 | "An input file must be specified with either -c or -dump.\n"); |
| 62 | return 1; |
| 63 | } |
| 64 | if (FLAGS_dump != "") { |
| 65 | fprintf(stderr, "FIXME: the -dump option is not yet implemented.\n"); |
| 66 | return 1; |
| 67 | } |
| 68 | |
| 69 | WavReader c_file(FLAGS_c); |
| 70 | // If the output format is uninitialized, use the input format. |
| 71 | int o_channels = FLAGS_o_channels; |
| 72 | if (!o_channels) |
| 73 | o_channels = c_file.num_channels(); |
| 74 | int o_sample_rate = FLAGS_o_sample_rate; |
| 75 | if (!o_sample_rate) |
| 76 | o_sample_rate = c_file.sample_rate(); |
| 77 | WavWriter o_file(FLAGS_o, o_sample_rate, o_channels); |
| 78 | |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 79 | Config config; |
| 80 | config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all)); |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 81 | |
| 82 | if (FLAGS_bf || FLAGS_all) { |
| 83 | if (FLAGS_mic_spacing <= 0) { |
| 84 | fprintf(stderr, |
| 85 | "mic_spacing must a positive value when beamforming is enabled.\n"); |
| 86 | return 1; |
| 87 | } |
| 88 | |
| 89 | const size_t num_mics = c_file.num_channels(); |
| 90 | std::vector<Point> array_geometry; |
| 91 | array_geometry.reserve(num_mics); |
| 92 | |
| 93 | for (size_t i = 0; i < num_mics; ++i) { |
| 94 | array_geometry.push_back(Point(0.0, i * FLAGS_mic_spacing, 0.0)); |
| 95 | } |
| 96 | |
| 97 | config.Set<Beamforming>(new Beamforming(true, array_geometry)); |
| 98 | } |
| 99 | |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 100 | scoped_ptr<AudioProcessing> ap(AudioProcessing::Create(config)); |
| 101 | if (FLAGS_dump != "") { |
| 102 | CHECK_EQ(kNoErr, ap->echo_cancellation()->Enable(FLAGS_aec || FLAGS_all)); |
| 103 | } else if (FLAGS_aec) { |
| 104 | fprintf(stderr, "-aec requires a -dump file.\n"); |
| 105 | return -1; |
| 106 | } |
| 107 | CHECK_EQ(kNoErr, ap->gain_control()->Enable(FLAGS_agc || FLAGS_all)); |
| 108 | CHECK_EQ(kNoErr, ap->gain_control()->set_mode(GainControl::kFixedDigital)); |
| 109 | CHECK_EQ(kNoErr, ap->high_pass_filter()->Enable(FLAGS_hpf || FLAGS_all)); |
| 110 | CHECK_EQ(kNoErr, ap->noise_suppression()->Enable(FLAGS_ns || FLAGS_all)); |
| 111 | if (FLAGS_ns_level != -1) |
| 112 | CHECK_EQ(kNoErr, ap->noise_suppression()->set_level( |
| 113 | static_cast<NoiseSuppression::Level>(FLAGS_ns_level))); |
| 114 | |
mgraczyk@chromium.org | 5a92b78 | 2015-01-15 01:28:36 +0000 | [diff] [blame] | 115 | printf("Input file: %s\nChannels: %d, Sample rate: %d Hz\n\n", |
| 116 | FLAGS_c.c_str(), c_file.num_channels(), c_file.sample_rate()); |
| 117 | printf("Output file: %s\nChannels: %d, Sample rate: %d Hz\n\n", |
| 118 | FLAGS_o.c_str(), o_file.num_channels(), o_file.sample_rate()); |
| 119 | |
andrew@webrtc.org | 08df9b2 | 2014-12-16 20:57:15 +0000 | [diff] [blame] | 120 | ChannelBuffer<float> c_buf(c_file.sample_rate() / kChunksPerSecond, |
| 121 | c_file.num_channels()); |
| 122 | ChannelBuffer<float> o_buf(o_file.sample_rate() / kChunksPerSecond, |
| 123 | o_file.num_channels()); |
| 124 | |
| 125 | const size_t c_length = static_cast<size_t>(c_buf.length()); |
| 126 | scoped_ptr<float[]> c_interleaved(new float[c_length]); |
| 127 | scoped_ptr<float[]> o_interleaved(new float[o_buf.length()]); |
| 128 | while (c_file.ReadSamples(c_length, c_interleaved.get()) == c_length) { |
| 129 | FloatS16ToFloat(c_interleaved.get(), c_length, c_interleaved.get()); |
| 130 | Deinterleave(c_interleaved.get(), c_buf.samples_per_channel(), |
| 131 | c_buf.num_channels(), c_buf.channels()); |
| 132 | |
| 133 | CHECK_EQ(kNoErr, |
| 134 | ap->ProcessStream(c_buf.channels(), |
| 135 | c_buf.samples_per_channel(), |
| 136 | c_file.sample_rate(), |
| 137 | LayoutFromChannels(c_buf.num_channels()), |
| 138 | o_file.sample_rate(), |
| 139 | LayoutFromChannels(o_buf.num_channels()), |
| 140 | o_buf.channels())); |
| 141 | |
| 142 | Interleave(o_buf.channels(), o_buf.samples_per_channel(), |
| 143 | o_buf.num_channels(), o_interleaved.get()); |
| 144 | FloatToFloatS16(o_interleaved.get(), o_buf.length(), o_interleaved.get()); |
| 145 | o_file.WriteSamples(o_interleaved.get(), o_buf.length()); |
| 146 | } |
| 147 | |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | } // namespace webrtc |
| 152 | |
| 153 | int main(int argc, char* argv[]) { |
| 154 | return webrtc::main(argc, argv); |
| 155 | } |