Add arbitrary microphone geometry input to audioproc_f test utility.

R=andrew@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/35889004

Cr-Commit-Position: refs/heads/master@{#8208}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8208 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_processing/test/audioproc_float.cc b/webrtc/modules/audio_processing/test/audioproc_float.cc
index f8059de..bbac9f1 100644
--- a/webrtc/modules/audio_processing/test/audioproc_float.cc
+++ b/webrtc/modules/audio_processing/test/audioproc_float.cc
@@ -9,6 +9,7 @@
  */
 
 #include <stdio.h>
+#include <sstream>
 #include <string>
 
 #include "gflags/gflags.h"
@@ -25,7 +26,12 @@
 DEFINE_int32(o_channels, 0, "Number of output channels. Defaults to input.");
 DEFINE_int32(o_sample_rate, 0, "Output sample rate in Hz. Defaults to input.");
 DEFINE_double(mic_spacing, 0.0,
-    "Microphone spacing in meters.  Used when beamforming is enabled");
+    "Alternate way to specify mic_positions. "
+    "Assumes uniform linear array with specified spacings.");
+DEFINE_string(mic_positions, "",
+    "Space delimited cartesian coordinates of microphones in meters. "
+    "The coordinates of each point are contiguous. "
+    "For a two element array: \"x1 y1 z1 x2 y2 z2\"");
 
 DEFINE_bool(aec, false, "Enable echo cancellation.");
 DEFINE_bool(agc, false, "Enable automatic gain control.");
@@ -48,6 +54,63 @@
 
 namespace webrtc {
 
+namespace {
+
+// Returns a vector<T> parsed from whitespace delimited values in to_parse,
+// or an empty vector if the string could not be parsed.
+template<typename T>
+std::vector<T> parse_list(std::string to_parse) {
+  std::vector<T> values;
+
+  std::istringstream str(to_parse);
+  std::copy(
+      std::istream_iterator<T>(str),
+      std::istream_iterator<T>(),
+      std::back_inserter(values));
+
+  return values;
+}
+
+// Parses the array geometry from the command line.
+//
+// If a vector with size != num_mics is returned, an error has occurred and an
+// appropriate error message has been printed to stdout.
+std::vector<Point> get_array_geometry(size_t num_mics) {
+  std::vector<Point> result;
+  result.reserve(num_mics);
+
+  if (FLAGS_mic_positions.length()) {
+    CHECK(FLAGS_mic_spacing == 0.0 &&
+        "mic_positions and mic_spacing should not both be specified");
+
+    const std::vector<float> values = parse_list<float>(FLAGS_mic_positions);
+    if (values.size() != 3 * num_mics) {
+      fprintf(stderr,
+          "Could not parse mic_positions or incorrect number of points.\n");
+    } else {
+      for (size_t i = 0; i < values.size(); i += 3) {
+        double x = values[i + 0];
+        double y = values[i + 1];
+        double z = values[i + 2];
+        result.push_back(Point(x, y, z));
+      }
+    }
+  } else {
+    if (FLAGS_mic_spacing <= 0) {
+      fprintf(stderr,
+          "mic_spacing must a positive value when beamforming is enabled.\n");
+    } else {
+      for (size_t i = 0; i < num_mics; ++i) {
+        result.push_back(Point(0.0, i * FLAGS_mic_spacing, 0.0));
+      }
+    }
+  }
+
+  return result;
+}
+
+}  // namespace
+
 int main(int argc, char* argv[]) {
   {
     const std::string program_name = argv[0];
@@ -80,18 +143,10 @@
   config.Set<ExperimentalNs>(new ExperimentalNs(FLAGS_ts || FLAGS_all));
 
   if (FLAGS_bf || FLAGS_all) {
-    if (FLAGS_mic_spacing <= 0) {
-      fprintf(stderr,
-          "mic_spacing must a positive value when beamforming is enabled.\n");
-      return 1;
-    }
-
     const size_t num_mics = c_file.num_channels();
-    std::vector<Point> array_geometry;
-    array_geometry.reserve(num_mics);
-
-    for (size_t i = 0; i < num_mics; ++i) {
-      array_geometry.push_back(Point(0.0, i * FLAGS_mic_spacing, 0.0));
+    const std::vector<Point> array_geometry = get_array_geometry(num_mics);
+    if (array_geometry.size() != num_mics) {
+      return 1;
     }
 
     config.Set<Beamforming>(new Beamforming(true, array_geometry));