shithub: sox

Download patch

ref: 364d4eb30c1d1501a3110066237415c0cd6bae35
parent: 47eb7870f1128c4e58162fbf18b836c5f93c0e6f
author: robs <robs>
date: Sun Dec 17 14:17:28 EST 2006

volume & clipping improvements

--- a/src/sox.c
+++ b/src/sox.c
@@ -73,10 +73,11 @@
  */
 
 static enum {SOX_CONCAT, SOX_MIX, SOX_MERGE} mode = SOX_CONCAT;
-static int clipped = 0;         /* Volume change clipping errors */
+static st_size_t mixing_clips = 0;
 static int writing = 1;         /* are we writing to a file? assume yes. */
 static bool repeatable_random = false;  /* Whether to invoke srand. */
 static st_globalinfo_t globalinfo = {false, 1};
+static char uservolume = 0;
 
 static int user_abort = 0;
 
@@ -97,19 +98,18 @@
     char *filetype;
     st_signalinfo_t info;
     double volume;
-    char uservolume;
+    st_size_t volume_clips;
     char *comment;
-} file_options_t;
+} * file_options_t;
 
 /* local forward declarations */
-static bool doopts(file_options_t *fo, int, char **);
+static bool doopts(file_options_t fo, int, char **);
 static void usage(char *) NORET;
 static void usage_effect(char *) NORET;
 static void process(void);
 static void print_input_status(int input);
 static void update_status(void);
-static void statistics(void);
-static st_sample_t volumechange(st_sample_t *buf, st_ssize_t ct, double vol);
+static void volumechange(st_sample_t * buf, st_ssize_t len, file_options_t fo);
 static void parse_effects(int argc, char **argv);
 static void check_effects(void);
 static int start_effects(void);
@@ -127,7 +127,7 @@
 #define MAX_FILES MAX_INPUT_FILES + 1
 
 /* Array's tracking input and output files */
-static file_options_t *file_opts[MAX_FILES];
+static file_options_t file_opts[MAX_FILES];
 static ft_t file_desc[MAX_FILES];
 static size_t file_count = 0;
 static size_t input_count = 0;
@@ -179,7 +179,7 @@
 
 int main(int argc, char **argv)
 {
-    file_options_t *fo;
+    file_options_t fo;
     size_t i;
 
     myname = argv[0];
@@ -202,12 +202,13 @@
             exit(1);
         }
 
-        fo = (file_options_t *)xcalloc(sizeof(file_options_t), 1);
+        fo = xcalloc(sizeof(*fo), 1);
         fo->info.size = -1;
         fo->info.encoding = ST_ENCODING_UNKNOWN;
         fo->info.channels = 0;
         fo->info.compression = HUGE_VAL;
         fo->volume = 1.0;
+        fo->volume_clips = 0;
         file_opts[file_count++] = fo;
 
         if (doopts(fo, argc, argv) == true) /* is null file? */
@@ -232,15 +233,13 @@
 
     for (i = 0; i < input_count; i++)
     {
-      if (mode == SOX_MIX) {
-        /* When mixing audio, default to input side volume
-         * adjustments that will make sure no clipping will
-         * occur.  Users most likely won't be happy with
-         * this and will want to override it.
-         */
-        if (!file_opts[i]->uservolume)
-            file_opts[i]->volume = 1.0 / input_count;
-      }
+      /* When mixing audio, default to input side volume
+       * adjustments that will make sure no clipping will
+       * occur.  Users most likely won't be happy with
+       * this and will want to override it.
+       */
+      if (mode == SOX_MIX && !uservolume)
+        file_opts[i]->volume = 1.0 / input_count;
       
       file_desc[i] = st_open_read(file_opts[i]->filename,
                                   &file_opts[i]->info, 
@@ -295,11 +294,18 @@
     signal(SIGTERM, sigint);
 
     process();
-    statistics();
 
-    for (i = 0; i < file_count; i++)
-        free(file_desc[i]);
+    if (mixing_clips > 0)
+      st_warn("-m (soxmix) clipped %u samples; decrease volume?", mixing_clips);
 
+    for (i = 0; i < file_count; i++) {
+      if (file_opts[i]->volume_clips > 0)
+        st_warn("%s: -v clipped %u samples; decrease volume?", file_opts[i]->filename,
+            file_opts[i]->volume_clips);
+      free(file_opts[i]);
+      free(file_desc[i]);
+    }
+
     if (status)
     {
         if (user_abort)
@@ -359,7 +365,7 @@
     {NULL, 0, NULL, 0}
 };
 
-static bool doopts(file_options_t * fo, int argc, char **argv)
+static bool doopts(file_options_t fo, int argc, char **argv)
 {
   while (true) {
     int i;          /* Needed since scanf %u allows negative numbers :( */
@@ -436,7 +442,7 @@
           cleanup();
           exit(1);
         }
-        fo->uservolume = 1;
+        uservolume = 1;
         if (fo->volume < 0.0)
           st_report("Volume adjustment is negative; "
                     "this will result in a phase change");
@@ -539,12 +545,13 @@
 
     for (f = 0; f < input_count; f++)
     {
-        st_report("Input file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
+        st_report("Input file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s, volume %g",
                   file_desc[f]->filename, file_desc[f]->info.rate,
                   st_sizes_str[(unsigned char)file_desc[f]->info.size],
                   st_encodings_str[(unsigned char)file_desc[f]->info.encoding],
                   file_desc[f]->info.channels,
-                  (file_desc[f]->info.channels > 1) ? "channels" : "channel");
+                  (file_desc[f]->info.channels > 1) ? "channels" : "channel",
+                  file_opts[f]->volume);
 
         if (file_desc[f]->comment)
             st_report("Input file %s: comment \"%s\"",
@@ -567,7 +574,7 @@
         st_loopinfo_t loops[ST_MAX_NLOOPS];
         double factor;
         int i;
-        file_options_t * options = file_opts[file_count-1];
+        file_options_t options = file_opts[file_count-1];
         char const * comment = NULL;
 
         if (options->info.rate == 0)
@@ -632,13 +639,14 @@
                 status = 1;
         }
 
-        st_report("Output file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
+        st_report("Output file %s: using sample rate %lu\n\tsize %s, encoding %s, %d %s, volume %g",
                   file_desc[file_count-1]->filename, 
                   file_desc[file_count-1]->info.rate,
                   st_sizes_str[(unsigned char)file_desc[file_count-1]->info.size],
                   st_encodings_str[(unsigned char)file_desc[file_count-1]->info.encoding],
                   file_desc[file_count-1]->info.channels,
-                  (file_desc[file_count-1]->info.channels > 1) ? "channels" : "channel");
+                  (file_desc[file_count-1]->info.channels > 1) ? "channels" : "channel",
+                  file_opts[file_count-1]->volume);
 
         if (file_desc[file_count-1]->comment)
             st_report("Output file: comment \"%s\"", 
@@ -747,14 +755,7 @@
                   continue;
                 }
             }
-          
-          /* Adjust input side volume based on value specified
-           * by user for this file.
-           */
-          if (file_opts[current_input]->volume != 1.0)
-            clipped += volumechange(efftab[0].obuf, 
-                                    efftab[0].olen,
-                                    file_opts[current_input]->volume);
+          volumechange(efftab[0].obuf, efftab[0].olen,file_opts[current_input]);
         } else if (mode == SOX_MIX) {
           for (f = 0; f < input_count; f++)
             {
@@ -773,13 +774,7 @@
               if (f == 0)
                 read_samples += efftab[0].olen;
               
-              /* Adjust input side volume based on value specified
-               * by user for this file.
-               */
-              if (file_opts[f]->volume != 1.0)
-                clipped += volumechange(ibuf[f], 
-                                        ilen[f],
-                                        file_opts[f]->volume);
+              volumechange(ibuf[f], ilen[f], file_opts[f]);
             }
           
           /* FIXME: Should report if the size of the reads are not
@@ -808,10 +803,10 @@
                   else
                     if (s < (st_size_t)ilen[f])
                       {
-                        double sample;
-                        sample = efftab[0].obuf[s] + ibuf[f][s];
-                        ST_SAMPLE_CLIP_COUNT(sample, clipped);
-                        efftab[0].obuf[s] = sample;
+                        double sample = efftab[0].obuf[s];
+                        sample += ibuf[f][s]; /* DON'T COMBINE WITH PREV LINE */
+                        efftab[0].obuf[s] =
+                            ST_ROUND_CLIP_COUNT(sample, mixing_clips);
                       }
                 }
             }
@@ -826,6 +821,7 @@
             }
             if ((st_size_t)ilen[f] > efftab[0].olen)
               efftab[0].olen = ilen[f];
+            volumechange(ibuf[f], ilen[f], file_opts[f]);
           }
           
           for (s = 0; s < efftab[0].olen; s++)
@@ -895,9 +891,8 @@
     for (f = 0; f < input_count; f++)
     {
         if (file_desc[f]->clippedCount != 0)
-        {
-          st_warn("%s: %u values clipped on input", file_desc[f]->filename, file_desc[f]->clippedCount);
-        }
+          st_warn("%s: input clipped %u samples", file_desc[f]->filename,
+              file_desc[f]->clippedCount);
 
         /* If problems closing input file, just warn user since
          * we are exiting anyways.
@@ -914,7 +909,10 @@
     {
         if (file_desc[f]->clippedCount != 0)
         {
-          st_warn("%s: %u values clipped on output", file_desc[f]->filename, file_desc[f]->clippedCount);
+          st_warn("%s: output clipped %u samples; decrease volume?",
+             (file_desc[f]->h->flags & ST_FILE_NOFEXT)?
+             file_desc[f]->h->names[0] : file_desc[f]->filename,
+             file_desc[f]->clippedCount);
         }
 
         /* problem closing output file, just warn user since we
@@ -1303,10 +1301,8 @@
       if (writing && (efftab[neffects-1].olen>efftab[neffects-1].odone))
       {
           /* Change the volume of this output data if needed. */
-          if (writing && file_opts[file_count-1]->volume != 1.0)
-              clipped += volumechange(efftab[neffects-1].obuf, 
-                                      efftab[neffects-1].olen,
-                                      file_opts[file_count-1]->volume);
+          volumechange(efftab[neffects-1].obuf, efftab[neffects-1].olen,
+                                      file_opts[file_count-1]);
 
           total = 0;
           do
@@ -1416,7 +1412,7 @@
      */
     if (input_eff > 0)
     {
-        st_debug("Effect return ST_EOF\n");
+        st_debug("Effect return ST_EOF");
         return ST_EOF;
     }
 
@@ -1439,7 +1435,7 @@
     /* I have no input data ? */
     if (efftab[e-1].odone == efftab[e-1].olen)
     {
-        st_debug("%s no data to pull to me!\n", efftab[e].name);
+        st_debug("%s no data to pull to me!", efftab[e].name);
         return 0;
     }
 
@@ -1639,9 +1635,8 @@
             clippedCount += efftab[e].clippedCount;
         }
         if (clippedCount != 0)
-        {
-          st_warn("%s: %u values clipped, maybe adjust volume?", efftab[e].name, clippedCount);
-        }
+          st_warn("%s clipped %u samples; decrease volume?", efftab[e].name,
+              clippedCount);
     }
 }
 
@@ -1726,27 +1721,14 @@
     fprintf(stderr, "\rTime: %02i:%05.2f [%02i:%05.2f] of %02i:%05.2f (% 5.1f%%) Output Buffer:% 7.2f%c", read_min, read_sec, left_min, left_sec, in_min, in_sec, completed, out_size, unit);
 }
 
-static void statistics(void) 
+/* Adjust volume based on value specified by the -v option for this file. */
+static void volumechange(st_sample_t * buf, st_ssize_t len, file_options_t fo)
 {
-    if (clipped > 0)
-        st_warn("Volume change clipped %d samples", clipped);
-}
-
-static st_sample_t volumechange(st_sample_t *buf, st_ssize_t ct, 
-                                double vol)
-{
-        double y;
-        st_sample_t *p,*top;
-        st_ssize_t clips=0;
-
-        p = buf;
-        top = buf+ct;
-        while (p < top) {
-            y = vol * *p;
-            ST_SAMPLE_CLIP_COUNT(y, clips);
-            *p++ = y;
-        }
-        return clips;
+  if (fo->volume != 1)
+    while (len--) {
+      double d = fo->volume * *buf;
+      *buf++ = ST_ROUND_CLIP_COUNT(d, fo->volume_clips);
+    }
 }
 
 static void usage(char *opt)