shithub: sox

Download patch

ref: 615fa4b79b233395393258f0c0893b6c19ad263f
parent: 3466e693fbb673e9c446acf8027086be378d905c
author: cbagwell <cbagwell>
date: Sat Sep 13 21:47:01 EDT 2008

Add support for specifying effects with a text file instead of command line.

--- a/ChangeLog
+++ b/ChangeLog
@@ -45,6 +45,8 @@
   o New -b option for the norm effect; can be used to fix stereo
     imbalance.  (robs)
   o Fix broken audio pass-through with noiseprof effect.  (robs)
+  o New --effects-file option to read effects and arguments from
+    a file instead of command line. (cbagwell)
 
 Other new features:
 
--- a/sox.1
+++ b/sox.1
@@ -560,6 +560,26 @@
 Show information about the specified file format.  The name
 \fBall\fR can be used to show information on all formats.
 .TP
+\fB\-\-buffer\fR \fBBYTES\fR, \fB\-\-input\-buffer\fR \fBBYTES\fR
+Set the size in bytes of the buffers used for processing audio (default 8192).
+.B \-\-buffer
+applies to input, effects, and output processing;
+.B \-\-input\-buffer
+applies only to input processing (for which it overrides
+.B \-\-buffer
+if both are given).
+.SP
+Be aware that large values for
+.B \-\-buffer
+will cause SoX to be become slow to respond to requests to terminate or to skip
+the current input file.
+.TP
+\fB\-\--effects\-file=\fIFILENAME\fR
+Specify a file containing the effects and their arguments to be used.
+Only the first line of the file is read and its format should be the same as when specifying effects on the command line.
+Each time a new input or output file is opened, the effects file
+is reread for latest values.
+.TP
 \fB\-\-interactive\fR
 Prompt before overwriting an existing file with the same name as that
 given for the output file.
@@ -578,20 +598,6 @@
 option is strongly recommended; a `shell' alias, script, or batch file
 may be an appropriate way of permanently enabling it.
 .TP
-\fB\-\-buffer\fR \fBBYTES\fR, \fB\-\-input\-buffer\fR \fBBYTES\fR
-Set the size in bytes of the buffers used for processing audio (default 8192).
-.B \-\-buffer
-applies to input, effects, and output processing;
-.B \-\-input\-buffer
-applies only to input processing (for which it overrides
-.B \-\-buffer
-if both are given).
-.SP
-Be aware that large values for
-.B \-\-buffer
-will cause SoX to be become slow to respond to requests to terminate or to skip
-the current input file.
-.TP
 \fB\-m\fR\^|\^\fB\-M\fR\^|\^\fB\-\-combine concatenate\fR\^|\^\fBmerge\fR\^|\^\fBmix\fR\^|\^\fBmix\-power\fR\^|\^\fBsequence\fR
 Select the input file combining method;
 .B \-m
@@ -601,6 +607,11 @@
 .SP
 See \fBInput File Combining\fR above for a description of the different
 combining methods.
+.TP
+\fB\-\-output single\fR\^|\^\fBmultiple\fR
+Select single or multiple output file mode.
+See \fBOutput Files\fR above for a description of the different
+output modes.
 .TP
 \fB\-\-plot gnuplot\fR\^|\^\fBoctave\fR\^|\^\fBoff\fR
 If not set to
--- a/src/sox.c
+++ b/src/sox.c
@@ -134,8 +134,9 @@
 static sox_effect_t *user_efftab[MAX_USER_EFF];
 static unsigned nuser_effects;
 static sox_effects_chain_t *effects_chain = NULL;
+static char *effects_filename = NULL;
+static void parse_effects(int argc, char **argv);
 
-
 /* Flowing */
 
 static sox_signalinfo_t combiner_signal, ofile_signal_options;
@@ -564,6 +565,122 @@
     exit(2); /* The effects chain should have displayed an error message */
 }
 
+static void delete_user_effects(void)
+{
+  unsigned i;
+  int j;
+
+  for (i = 0; i < nuser_effects; i++) 
+  {
+    if (user_effargs[i].name)
+      free(user_effargs[i].name);
+    user_effargs[i].name = NULL;
+    for (j = 0; j < user_effargs[i].argc; j++)
+    {
+      if (user_effargs[i].argv[j])
+        free(user_effargs[i].argv[j]);
+      user_effargs[i].argv[i] = NULL;
+    }
+    user_effargs[i].argc = 0;
+  }
+  nuser_effects = 0;
+} /* delete_user_effects */
+
+static int strtoargv(char *s, char *(*argv)[])
+{
+    int argc = 0;
+
+    if (!s) return 0;
+
+    while (*s)
+    {
+        int quote_mode;
+
+        /* Skip past any white space */
+        while (*s == ' ' || *s == '\t')
+            s++;
+
+        /* Stop processing if no more data */
+        if (!*s)
+            break;
+
+        /* If starts with quote then start quote mode.  This
+         * will ignore seperators until a final quote is seen.
+         * Don't put quote into the argument.
+         */
+        if (*s == '"')
+        {
+            quote_mode = 1;
+            s++;
+        }
+        else
+            quote_mode = 0;
+
+        (*argv)[argc] = s;
+
+        /* Scan for seperator and when overwrite with 0 */
+        while (*s)
+        {
+            /* Treat quote as final seperator; even if there is
+             * more data right after it.
+             * TODO: Process \" and \\ so that user can
+             * have quotes inside quotes.  Tricky to do though.
+             */
+            if (quote_mode && *s == '"')
+                break;
+
+            if (!quote_mode && (*s == ' ' || *s == '\t'))
+                break;
+            s++;
+        }
+        *s = 0;
+        s++;
+        argc += 1;
+    }
+
+    return argc;
+} /* strtoargv */
+
+static void read_user_effects(char *filename)
+{
+    FILE *file = fopen(filename, "rt");
+    char s[1025];
+    int argc;
+    char *argv[256];
+    int len;
+
+    delete_user_effects();
+
+    if (file == NULL)
+    {
+        sox_fail("Cannot open effects file %s", filename);
+        exit(1);
+    }
+
+    sox_report("Reading effects from file %s", filename);
+
+    if (fgets(s, 1024, file) == NULL)
+    {
+        sox_fail("Error reading effects file %s", filename);
+        exit(2);
+    }
+    len = strlen(s);
+    if (s[len-1] == '\n')
+        s[len-1] = 0;
+
+    argc = strtoargv(s, &argv);
+
+    /* parse_effects normally parses options from command line.
+     * Reset opt index so it thinks its back at beginning of
+     * main()'s argv[].
+     */
+    optind = 0;
+    parse_effects(argc, argv);
+
+    fclose(file);
+
+} /* read_user_effects */
+
 /* Creates users effects and passes in user specified options.
  * This is done without putting anything into the effects chain
  * because an effect may set the effp->in_format and we may want
@@ -580,6 +697,16 @@
   unsigned i;
   sox_effect_t *effp;
 
+  /* If user specified an effects filename then use that file
+   * to load user effects.  Free any previously specified options
+   * from the command line.  This also means that effects will
+   * be reloaded each time a new input or output file is opened.
+   */
+  if (effects_filename)
+  {
+    read_user_effects(effects_filename);
+  }
+
   for (i = 0; i < nuser_effects; i++) 
   {
       effp = sox_create_effect(sox_find_effect(user_effargs[i].name));
@@ -1200,6 +1327,7 @@
 "--buffer BYTES  set the size of all processing buffers (default 8192)",
 "--combine concatenate  concatenate multiple input files (default for sox, rec)",
 "--combine sequence  sequence multiple input files (default for play)",
+"--effects-file FILENAME  file containing effects and options",
 "-h, --help      display version number and usage information",
 "--help-effect NAME  display usage of specified effect; use `all' to display all",
 "--help-format NAME  display info on specified format; use `all' to display all",
@@ -1408,6 +1536,7 @@
     {"replay-gain"     , required_argument, NULL, 0},
     {"version"         ,       no_argument, NULL, 0},
     {"output"          , required_argument, NULL, 0},
+    {"effects-file"    , required_argument, NULL, 0},
 
     {"channels"        , required_argument, NULL, 'c'},
     {"compression"     , required_argument, NULL, 'C'},
@@ -1558,6 +1687,11 @@
       case 13:
         output_method = enum_option(option_index, output_methods);
         break;
+
+      case 14:
+        effects_filename = strdup(optarg);
+        break;
+
       }
       break;
 
@@ -2029,6 +2163,7 @@
   else process();
 
   sox_delete_effects_chain(effects_chain);
+  delete_user_effects();
 
   for (i = 0; i < file_count; ++i)
     if (files[i]->ft->clips != 0)