shithub: sox

Download patch

ref: 38f21528d72f4fc3f5408fcd5104190d1d4e588c
parent: 2423ba7e9e5941c6e4549e27f2d7c9a6d2e7da23
author: robs <robs>
date: Sun Feb 17 15:33:21 EST 2008

heuristic to set album replay-gain mode

--- a/ChangeLog
+++ b/ChangeLog
@@ -38,6 +38,8 @@
   o Added soxi utility to extract/display file header fields.  (robs)
   o Added pkg-config support. (Pascal Giard)
   o Added simple V.U. meter.  (robs)
+  o Added simple heuristic to detect when playing an album and set
+    the default replay-gain mode to `album'.  (robs)
 
 Bug fixes:
 
--- a/sox.1
+++ b/sox.1
@@ -542,11 +542,19 @@
 \fB\-\-replay\-gain track\fR\^|\^\fBalbum\fR\^|\^\fBoff\fR
 Select whether or not to apply replay-gain adjustment to input files.
 The default is
+.B off
+for
+.B sox
+and
+.BR rec ,
+.B album
+for
+.B play
+where (at least) the first two input files are tagged with the same Artist and
+Album names, and
 .B track
 for
 .B play
-and
-.B off
 otherwise.
 .TP
 \fB\-S\fR, \fB\-\-show\-progress\fR
--- a/src/sox.c
+++ b/src/sox.c
@@ -76,6 +76,11 @@
 static sox_bool interactive = sox_false;
 static sox_bool uservolume = sox_false;
 typedef enum {RG_off, RG_track, RG_album} rg_mode;
+static enum_item const rg_modes[] = {
+  ENUM_ITEM(RG_,off)
+  ENUM_ITEM(RG_,track)
+  ENUM_ITEM(RG_,album)
+  {0, 0}};
 static rg_mode replay_gain_mode = RG_off;
 static sox_option_t show_progress = SOX_OPTION_DEFAULT;
 
@@ -91,6 +96,7 @@
   sox_signalinfo_t signal;
   double volume;
   double replay_gain;
+  rg_mode replay_gain_mode;
   comments_t comments;
 
   sox_format_t * ft;  /* libSoX file descriptor */
@@ -227,7 +233,8 @@
   }
 
   if (f && f->replay_gain != HUGE_VAL)
-    fprintf(output, "Replay gain    : %+g dB\n" , f->replay_gain);
+    fprintf(output, "Replay gain    : %+g dB (%s)\n" , f->replay_gain,
+        find_enum_value(f->replay_gain_mode, rg_modes)->text);
   if (f && f->volume != HUGE_VAL)
     fprintf(output, "Level adjust   : %g (linear gain)\n" , f->volume);
 
@@ -1035,12 +1042,6 @@
   ENUM_ITEM(sox_,merge)
   {0, 0}};
 
-static enum_item const rg_modes[] = {
-  ENUM_ITEM(RG_,off)
-  ENUM_ITEM(RG_,track)
-  ENUM_ITEM(RG_,album)
-  {0, 0}};
-
 enum {ENDIAN_little, ENDIAN_big, ENDIAN_swap};
 static enum_item const endian_options[] = {
   ENUM_ITEM(ENDIAN_,little)
@@ -1422,6 +1423,7 @@
     for (i = 0; i < n; ++i) {
       if (strncasecmp(comments[i], target, strlen(target)) == 0) {
         f->replay_gain = atof(comments[i] + strlen(target));
+        f->replay_gain_mode = rg;
         return;
       }
     }
@@ -1438,6 +1440,11 @@
   }
 }
 
+static sox_bool cmp_comment_text(char const * c1, char const * c2)
+{
+  return c1 && c2 && !strcasecmp(c1, c2);
+}
+
 int main(int argc, char **argv)
 {
   size_t i;
@@ -1508,8 +1515,19 @@
         (files[j]->ft->handler->flags & SOX_FILE_DEVICE) != 0 &&
         (files[j]->ft->handler->flags & SOX_FILE_PHONY) == 0)
       show_progress = SOX_OPTION_YES;
-    set_replay_gain(files[j]->ft->comments, f);
   }
+  /* Simple heuristic to determine if replay-gain should be in album mode */
+  if (sox_mode == sox_play && replay_gain_mode == RG_track && input_count > 1 &&
+      cmp_comment_text(
+        find_comment(files[0]->ft->comments, "artist"),
+        find_comment(files[1]->ft->comments, "artist")) &&
+      cmp_comment_text(
+        find_comment(files[0]->ft->comments, "album"),
+        find_comment(files[1]->ft->comments, "album")))
+    replay_gain_mode = RG_album;
+
+  for (i = 0; i < input_count; i++)
+    set_replay_gain(files[i]->ft->comments, files[i]);
   signal(SIGINT, SIG_DFL);
 
   /* Loop through the rest of the arguments looking for effects */
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -239,6 +239,7 @@
 comments_t copy_comments(comments_t comments);
 void delete_comments(comments_t * comments);
 char * cat_comments(comments_t comments);
+char const * find_comment(comments_t comments, char const * id);
 
 
 
--- a/src/util.c
+++ b/src/util.c
@@ -221,3 +221,13 @@
   }
   return result;
 }
+
+char const * find_comment(comments_t comments, char const * id)
+{
+  size_t len = strlen(id);
+
+  if (comments) for (;*comments; ++comments)
+    if (!strncasecmp(*comments, id, len) && (*comments)[len] == '=')
+      return *comments + len + 1;
+  return NULL;
+}