From 32fe572b0053eb1cb694d945766a65de3278d7a2 Mon Sep 17 00:00:00 2001
The sox program currently uses soxconfig.h as the basis for some of its
runtime behavior. It should instead be less tightly coupled from libsox,
and should get runtime information about libsox by querying libsox.
This adds a new function, sox_version_info(), which reports information about
how libsox was compiled and what options it supports. sox now uses the data
from sox_version_info instead of using #ifdefs.

Also added variable sox_globals.use_threads. This is used instead of having
the client program call omp_set_num_threads. This decouples the underlying
threading implementation used by libsox from the threading implementation used
by the client, i.e. libsox links against OMP, but sox no longer needs to do so.
---
 msvc10/.gitignore      |   11 +++--
 msvc10/SoX/soxconfig.h |    2 +-
 msvc9/Sox/soxconfig.h  |    2 +-
 src/effects.c          |   50 +++++++++++++--------
 src/libsox.c           |   76 ++++++++++++++++++++++++++++++++-
 src/sox.c              |  112 +++++++++++++++++++++++++-----------------------
 src/sox.h              |   23 ++++++++++
 7 files changed, 197 insertions(+), 79 deletions(-)

diff --git a/msvc10/.gitignore b/msvc10/.gitignore
index 6dbf1ee..d01a759 100644
--- a/msvc10/.gitignore
+++ b/msvc10/.gitignore
@@ -1,7 +1,10 @@
 *.user
-Sox.suo
-Sox.ncb
-Sox.sdf
-Sox.opensdf
+Debug
+ipch
 Makefile
 Makefile.in
+Release
+Sox.ncb
+Sox.opensdf
+Sox.sdf
+Sox.suo
diff --git a/msvc10/SoX/soxconfig.h b/msvc10/SoX/soxconfig.h
index 2404369..00d7005 100644
--- a/msvc10/SoX/soxconfig.h
+++ b/msvc10/SoX/soxconfig.h
@@ -18,7 +18,7 @@
 /* Used only by sox.c: */
 #define MORE_INTERACTIVE
 
-#define PACKAGE_VERSION "14.3.1-msvc"
+#define PACKAGE_EXTRA "msvc"
 
 /* Special behavior defined by win32-ltdl: "./" is replaced with the name of the
    directory containing sox.exe. */
diff --git a/msvc9/Sox/soxconfig.h b/msvc9/Sox/soxconfig.h
index 2404369..00d7005 100644
--- a/msvc9/Sox/soxconfig.h
+++ b/msvc9/Sox/soxconfig.h
@@ -18,7 +18,7 @@
 /* Used only by sox.c: */
 #define MORE_INTERACTIVE
 
-#define PACKAGE_VERSION "14.3.1-msvc"
+#define PACKAGE_EXTRA "msvc"
 
 /* Special behavior defined by win32-ltdl: "./" is replaced with the name of the
    directory containing sox.exe. */
diff --git a/src/effects.c b/src/effects.c
index 71b8828..25ad4be 100644
--- a/src/effects.c
+++ b/src/effects.c
@@ -223,29 +223,41 @@ static int flow_effect(sox_effects_chain_t * chain, size_t n)
         chain->ibufc[f][i / effp->flows] = *ibuf++;
 
 #ifdef HAVE_OPENMP
-    #pragma omp parallel for
-#endif
-    for (f = 0; f < (int)effp->flows; ++f) {
-      size_t idonec = idone / effp->flows;
-      size_t odonec = obeg / effp->flows;
-      int eff_status_c = effp->handler.flow(&chain->effects[n][f],
-          chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
-#ifndef HAVE_OPENMP
-      if (f && (idonec != idone_last || odonec != odone_last)) {
-        lsx_fail("flowed asymmetrically!");
-        effstatus = SOX_EOF;
+    if (sox_globals.use_threads && effp->flows > 1)
+    {
+      #pragma omp parallel for
+      for (f = 0; f < (int)effp->flows; ++f) {
+        size_t idonec = idone / effp->flows;
+        size_t odonec = obeg / effp->flows;
+        int eff_status_c = effp->handler.flow(&chain->effects[n][f],
+            chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
+        if (!f) {
+          idone_last = idonec;
+          odone_last = odonec;
+        }
+
+        if (eff_status_c != SOX_SUCCESS)
+          effstatus = SOX_EOF;
       }
-      idone_last = idonec;
-      odone_last = odonec;
-#else
-      if (!f) {
+    }
+    else /* sox_globals.use_threads */
+#endif
+    {
+      for (f = 0; f < (int)effp->flows; ++f) {
+        size_t idonec = idone / effp->flows;
+        size_t odonec = obeg / effp->flows;
+        int eff_status_c = effp->handler.flow(&chain->effects[n][f],
+            chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
+        if (f && (idonec != idone_last || odonec != odone_last)) {
+          lsx_fail("flowed asymmetrically!");
+          effstatus = SOX_EOF;
+        }
         idone_last = idonec;
         odone_last = odonec;
-      }
-#endif
 
-      if (eff_status_c != SOX_SUCCESS)
-        effstatus = SOX_EOF;
+        if (eff_status_c != SOX_SUCCESS)
+          effstatus = SOX_EOF;
+      }
     }
 
     for (i = 0; i < odone_last; ++i)
diff --git a/src/libsox.c b/src/libsox.c
index 2864830..d60bb9f 100644
--- a/src/libsox.c
+++ b/src/libsox.c
@@ -32,6 +32,79 @@ const char *sox_version(void)
   return(versionstr);
 }
 
+sox_version_info_t const * sox_version_info(void)
+{
+#define STRINGIZE1(x) #x
+#define STRINGIZE(x) STRINGIZE1(x)
+    static char arch[30];
+    static sox_version_info_t info = {
+        /* size */
+        sizeof(sox_version_info_t),
+        /* flags */
+        (sox_version_flags_t)(
+#if HAVE_POPEN
+        sox_version_have_popen +
+#endif
+#if  HAVE_MAGIC
+        sox_version_have_magic +
+#endif
+#if HAVE_OPENMP
+        sox_version_have_threads +
+#endif
+        sox_version_none),
+        /* version_code */
+        SOX_LIB_VERSION_CODE,
+        /* version */
+        NULL,
+        /* sox_version_extra */
+#ifdef PACKAGE_EXTRA
+        PACKAGE_EXTRA,
+#else
+        NULL,
+#endif
+        /* sox_time */
+        __DATE__ " " __TIME__,
+        /* sox_distro */
+#ifdef DISTRO
+        DISTRO,
+#else
+        NULL,
+#endif
+        /* sox_compiler */
+#if defined __GNUC__
+        "gcc " __VERSION__,
+#elif defined _MSC_VER
+        "msvc " STRINGIZE(_MSC_FULL_VER),
+#elif defined __SUNPRO_C
+    fprintf(file, "sun c " STRINGIZE(__SUNPRO_C),
+#else
+        NULL,
+#endif
+        /* sox_arch */
+        NULL
+    };
+
+    if (!info.version)
+    {
+        info.version = sox_version();
+    }
+
+    if (!info.arch)
+    {
+        snprintf(arch, sizeof(arch), "%u%u%u%u %u%u %u%u %c %s",
+            (unsigned)sizeof(char), (unsigned)sizeof(short),
+            (unsigned)sizeof(long), (unsigned)sizeof(off_t),
+            (unsigned)sizeof(float), (unsigned)sizeof(double),
+            (unsigned)sizeof(int *), (unsigned)sizeof(int (*)(void)),
+            MACHINE_IS_BIGENDIAN ? 'B' : 'L',
+            (info.flags & sox_version_have_threads) ? "OMP" : "");
+        arch[sizeof(arch) - 1] = 0;
+        info.arch = arch;
+    }
+
+    return &info;
+}
+
 /* Default routine to output messages; can be overridden */
 static void output_message(
     unsigned level, const char *filename, const char *fmt, va_list ap)
@@ -53,7 +126,8 @@ sox_globals_t sox_globals = {
   NULL,            /* char const * stdout_in_use_by */
   NULL,            /* char const * subsystem */
   NULL,            /* char       * tmp_path */
-  sox_false        /* sox_bool     use_magic */
+  sox_false,       /* sox_bool     use_magic */
+  sox_false        /* sox_bool     use_threads */
 };
 
 char const * sox_strerror(int sox_errno)
diff --git a/src/sox.c b/src/sox.c
index 6db9e17..26e8c0a 100644
--- a/src/sox.c
+++ b/src/sox.c
@@ -21,7 +21,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "soxomp.h"  /* Make this 1st in list (for soxconfig) */
+#include "soxconfig.h"
 #include "sox.h"
 #include "util.h"
 #include "sgetopt.h"
@@ -201,10 +201,6 @@ static sox_bool user_restart_eff = sox_false;
 static int success = 0;
 static sox_sample_t omax[2], omin[2];
 
-/* Multi-processing */
-
-static sox_bool single_threaded = sox_true;
-
 #ifdef HAVE_TERMIOS_H
 #include <termios.h>
 static struct termios original_termios;
@@ -1679,38 +1675,28 @@ static void display_SoX_version(FILE * file)
 #if HAVE_SYS_UTSNAME_H
   struct utsname uts;
 #endif
+  const sox_version_info_t* info = sox_version_info();
 
-  fprintf(file, "%s: SoX v%s\n", myname, PACKAGE_VERSION);
+  fprintf(file, "%s:      SoX v%s%s%s\n",
+      myname,
+      info->version,
+      info->version_extra ? "-" : "",
+      info->version_extra ? info->version_extra : "");
 
   if (sox_globals.verbosity > 3) {
-    fprintf(file, "time:  %s %s\n", __DATE__, __TIME__);
-#if HAVE_DISTRO
-    fprintf(file, "issue: %s\n", DISTRO);
-#endif
+    if (info->time)
+      fprintf(file, "time:     %s\n", info->time);
+    if (info->distro)
+      fprintf(file, "issue:    %s\n", info->distro);
 #if HAVE_SYS_UTSNAME_H
     if (!uname(&uts))
-      fprintf(file, "uname: %s %s %s %s %s\n", uts.sysname, uts.nodename,
+      fprintf(file, "uname:    %s %s %s %s %s\n", uts.sysname, uts.nodename,
           uts.release, uts.version, uts.machine);
 #endif
-#if defined __GNUC__
-    fprintf(file, "gcc:   %s\n", __VERSION__);
-#elif defined _MSC_VER
-    fprintf(file, "msc:   %u\n", _MSC_VER);
-#elif defined __SUNPRO_C
-    fprintf(file, "sun c: %x\n", __SUNPRO_C);
-#endif
-    fprintf(file, "arch:  %lu%lu%lu%lu %lu%lu %lu%lu %c %s\n",
-        (unsigned long)sizeof(char), (unsigned long)sizeof(short),
-        (unsigned long)sizeof(long), (unsigned long)sizeof(off_t),
-        (unsigned long)sizeof(float), (unsigned long)sizeof(double),
-        (unsigned long)sizeof(int *), (unsigned long)sizeof(int (*)(void)),
-        "LB"[MACHINE_IS_BIGENDIAN],
-#ifdef HAVE_OPENMP
-        "OMP"
-#else
-        ""
-#endif
-        );
+    if (info->compiler)
+        fprintf(file, "compiler: %s\n", info->compiler);
+    if (info->arch)
+        fprintf(file, "arch:     %s\n", info->arch);
   }
 }
 
@@ -1777,18 +1763,21 @@ static void display_supported_effects(void)
 
 static void usage(char const * message)
 {
+  const sox_version_info_t * info = sox_version_info();
   size_t i;
-  static char const * const lines[] = {
+  static char const * const lines1[] = {
 "SPECIAL FILENAMES (infile, outfile):",
 "-                        Pipe/redirect input/output (stdin/stdout); may need -t",
 "-d, --default-device     Use the default audio device (where available)",
 "-n, --null               Use the `null' file handler; e.g. with synth effect",
-"-p, --sox-pipe           Alias for `-t sox -'",
-#ifdef HAVE_POPEN
+"-p, --sox-pipe           Alias for `-t sox -'"
+  };
+  static char const * const linesPopen[] = {
 "\nSPECIAL FILENAMES (infile only):",
 "\"|program [options] ...\" Pipe input from external program (where supported)",
-"http://server/file       Use the given URL as input file (where supported)",
-#endif
+"http://server/file       Use the given URL as input file (where supported)"
+  };
+  static char const * const lines2[] = {
 "",
 "GLOBAL OPTIONS (gopts) (can be specified at any point before the first effect):",
 "--buffer BYTES           Set the size of all processing buffers (default 8192)",
@@ -1806,10 +1795,15 @@ static void usage(char const * message)
 "--no-clobber             Prompt to overwrite output file",
 "-m, --combine mix        Mix multiple input files (instead of concatenating)",
 "--combine mix-power      Mix to equal power (instead of concatenating)",
-"-M, --combine merge      Merge multiple input files (instead of concatenating)",
-"--magic                  Use `magic' file-type detection",
-"--multi-threaded         Enable parallel effects channels processing (where",
-"                         available)",
+"-M, --combine merge      Merge multiple input files (instead of concatenating)"
+  };
+  static char const * const linesMagic[] = {
+"--magic                  Use `magic' file-type detection"
+  };
+  static char const * const linesThreads[] = {
+"--multi-threaded         Enable parallel effects channels processing"
+  };
+  static char const * const lines3[] = {
 "--norm                   Guard (see --guard) & normalise",
 "--play-rate-arg ARG      Default `rate' argument for auto-resample with `play'",
 "--plot gnuplot|octave    Generate script to plot response of filter effect",
@@ -1850,7 +1844,9 @@ static void usage(char const * message)
 "--add-comment TEXT       Append output file comment",
 "--comment TEXT           Specify comment text for the output file",
 "--comment-file FILENAME  File containing comment text for the output file",
+#if HAVE_GLOB_H
 "--no-glob                Don't `glob' wildcard match the following filename",
+#endif
 ""};
 
   if (!(sox_globals.verbosity > 2)) {
@@ -1863,8 +1859,21 @@ static void usage(char const * message)
 
   printf("Usage summary: [gopts] [[fopts] infile]... [fopts]%s [effect [effopt]]...\n\n",
          sox_mode == sox_play? "" : " outfile");
-  for (i = 0; i < array_length(lines); ++i)
-    puts(lines[i]);
+  for (i = 0; i < array_length(lines1); ++i)
+    puts(lines1[i]);
+  if (info->flags & sox_version_have_popen)
+    for (i = 0; i < array_length(linesPopen); ++i)
+      puts(linesPopen[i]);
+  for (i = 0; i < array_length(lines2); ++i)
+    puts(lines2[i]);
+  if (info->flags & sox_version_have_magic)
+    for (i = 0; i < array_length(linesMagic); ++i)
+      puts(linesMagic[i]);
+  if (info->flags & sox_version_have_threads)
+    for (i = 0; i < array_length(linesThreads); ++i)
+      puts(linesThreads[i]);
+  for (i = 0; i < array_length(lines3); ++i)
+    puts(lines3[i]);
   display_supported_formats();
   display_supported_effects();
   printf("EFFECT OPTIONS (effopts): effect dependent; see --help-effect\n");
@@ -2133,6 +2142,7 @@ static int enum_option(int option_index, lsx_enum_item const * items)
 
 static char parse_gopts_and_fopts(file_t * f, int argc, char **argv)
 {
+  const sox_version_info_t* info = sox_version_info();
   while (sox_true) {
     int c, option_index;
     int i; /* sscanf silently accepts negative numbers for %u :( */
@@ -2203,18 +2213,19 @@ static char parse_gopts_and_fopts(file_t * f, int argc, char **argv)
       case 14: break;
       case 15: effects_filename = strdup(lsx_optarg); break;
       case 16: sox_globals.tmp_path = strdup(lsx_optarg); break;
-      case 17: single_threaded = sox_true; break;
+      case 17: sox_globals.use_threads = sox_false; break;
       case 18: f->signal.length = SOX_IGNORE_LENGTH; break;
       case 19: do_guarded_norm = is_guarded = sox_true; break;
-#if HAVE_MAGIC
-      case 20: sox_globals.use_magic = sox_true; break;
-#else
-      case 20: lsx_warn("this build of SoX does not include `magic'"); break;
-#endif
+      case 20:
+        if (info->flags & sox_version_have_magic)
+          sox_globals.use_magic = sox_true;
+        else
+          lsx_warn("this build of SoX does not include `magic'");
+        break;
       case 21: play_rate_arg = strdup(lsx_optarg); break;
       case 22: no_clobber = sox_false; break;
       case 23: no_clobber = sox_true; break;
-      case 24: single_threaded = sox_false; break;
+      case 24: sox_globals.use_threads = sox_true; break;
       }
       break;
 
@@ -2730,11 +2741,6 @@ int main(int argc, char **argv)
   }
 #endif
 
-#ifdef HAVE_OPENMP
-  if (single_threaded)
-    omp_set_num_threads(1);
-#endif
-
   if (sox_globals.verbosity > 2)
     display_SoX_version(stderr);
 
diff --git a/src/sox.h b/src/sox.h
index da7e19f..824641c 100644
--- a/src/sox.h
+++ b/src/sox.h
@@ -45,6 +45,28 @@ extern "C" {
 
 const char *sox_version(void);   /* Returns version number */
 
+typedef enum { /* Flags indicating whether optional features are present in this build of SoX */
+    sox_version_none = 0,
+    sox_version_have_popen = 1,
+    sox_version_have_magic = 2,
+    sox_version_have_threads = 4
+} sox_version_flags_t;
+
+typedef struct { /* Information about this build of SoX */
+    unsigned     size;         /* sizeof(sox_version_info_t) */
+    sox_version_flags_t flags; /* feature flags */
+    unsigned     version_code; /* version number, SOX_LIB_VERSION_CODE i.e. 0x140400 */
+    const char * version;      /* version string, sox_version() i.e. "14.4.0" */
+    const char * version_extra;/* version info or null, PACKAGE_EXTRA i.e. "beta" */
+    const char * time;         /* build time, __DATE__ __TIME__ i.e. "Jan  7 2010 03:31:50" */
+    const char * distro;       /* distro or null, DISTRO i.e. Debian */
+    const char * compiler;     /* compiler info or null, i.e. msvc: 1500 */
+    const char * arch;         /* arch: 1248 48 44 L OMP */
+    /* new info should be added at the end for version backwards-compatibility. */
+} sox_version_info_t;
+
+sox_version_info_t const * sox_version_info(void); /* gets information about libsox */
+
 #define SOX_SUCCESS 0            /* Function succeeded (= 0) */
 #define SOX_EOF (-1)             /* End Of File or other error (= -1) */
 
@@ -192,6 +214,7 @@ typedef struct { /* Global parameters (for effects & formats) */
   char const * subsystem;        /* tracks the name of the handler currently writing an output message */
   char       * tmp_path;         /* client-configured path to use for temporary files */
   sox_bool     use_magic;        /* true if client has requested use of 'magic' file-type detection */
+  sox_bool     use_threads;      /* true if client has requested parallel effects processing */
 } sox_globals_t;
 extern sox_globals_t sox_globals; /* the SoX global settings */
 
--
1.7.4.msysgit.0