shithub: sox

Download patch

ref: cdf18af4ee2c8ebda974ed8e957c979ce0599b42
parent: 8faf57a9681a9e9d86e52bc472c1d9e2ee286ab0
author: robs <robs>
date: Sat Nov 22 05:23:49 EST 2008

soxi enhancements

--- a/ChangeLog
+++ b/ChangeLog
@@ -26,7 +26,7 @@
 
 Other new features:
 
-  o 
+  o New bitrate, time in seconds, & total options for soxi.  (robs)
 
 Other bug fixes:
 
--- a/soxi.1
+++ b/soxi.1
@@ -33,7 +33,7 @@
 .SH NAME
 SoXI \- Sound eXchange Information, display sound file metadata
 .SH SYNOPSIS
-\fBsoxi\fR [\fB\-V\fR[\fIlevel\fR]] [\fB\-t\fR\^|\^\fB\-r\fR\^|\^\fB\-c\fR\^|\^\fB\-s\fR\^|\^\fB\-d\fR\^|\^\fB\-b\fR\^|\^\fB\-e\fR\^|\^\fB\-a\fR] \fIinfile1\fR ...
+\fBsoxi\fR [\fB\-V\fR[\fIlevel\fR]] [\fB\-T\fR] [\fB\-t\fR\^|\^\fB\-r\fR\^|\^\fB\-c\fR\^|\^\fB\-s\fR\^|\^\fB\-d\fR\^|\^\fB\-D\fR\^|\^\fB\-b\fR\^|\^\fB\-B\fR\^|\^\fB\-e\fR\^|\^\fB\-a\fR] \fIinfile1\fR ...
 .SH DESCRIPTION
 Displays information from the header of a given audio file or files.
 Supported audio file types are listed and described in
@@ -51,6 +51,17 @@
 .BR sox (1)
 for details.
 .TP
+\fB\-T\fR
+Used with multiple files; changes the behaviour of
+.BR \-s ,
+.B \-d
+and
+.B \-D
+to display the total across all given files.
+Note that when used with
+.B \-s
+with files with different sampling rates, this is of dubious value.
+.TP
 \fB\-t\fR
 Show detected file-type.
 .TP
@@ -67,8 +78,14 @@
 Show duration in hours, minutes and seconds (0 if unavailable).
 Equivalent to number of samples divided by the sample-rate.
 .TP
+\fB\-D\fR
+Show duration in seconds (0 if unavailable).
+.TP
 \fB\-b\fR
 Show number of bits per sample.
+.TP
+\fB\-B\fR
+Show the bitrate averaged over the whole file (0 if unavailable).
 .TP
 \fB\-e\fR
 Show the name of the audio encoding.
--- a/src/sox.c
+++ b/src/sox.c
@@ -2222,24 +2222,42 @@
     add_file(&opts, device_name(opts.filetype));
 }
 
-typedef enum {Full,
-  Type, Rate, Channels, Samples, Duration, Bits, Encoding, Annotation} soxi_t;
+static double soxi_total;
+static size_t soxi_file_count;
 
-static int soxi1(soxi_t * type, char * filename)
+typedef enum {Full, Type, Rate, Channels, Samples, Duration, Duration_secs,
+    Bits, Bitrate, Encoding, Annotation} soxi_t;
+
+static int soxi1(soxi_t const * type, char * filename)
 {
   size_t ws;
+  double secs;
   sox_format_t * ft = sox_open_read(filename, NULL, NULL, NULL);
 
   if (!ft)
     return 1;
   ws = ft->signal.length / max(ft->signal.channels, 1);
+  secs = (double)ws / max(ft->signal.rate, 1);
+  ++soxi_file_count;
+  if (soxi_total >= 0 && !ws)
+    soxi_total = -2;
+  if (soxi_total >= 0) soxi_total += *type == Samples? ws : secs;
+
   switch (*type) {
     case Type: printf("%s\n", ft->filetype); break;
     case Rate: printf("%g\n", ft->signal.rate); break;
     case Channels: printf("%u\n", ft->signal.channels); break;
-    case Samples: printf("%lu\n", (unsigned long)ws); break;
-    case Duration: printf("%s\n", str_time((double)ws / max(ft->signal.rate, 1))); break;
+    case Samples: if (soxi_total ==-1) printf("%lu\n",(unsigned long)ws); break;
+    case Duration: if (soxi_total ==-1) printf("%s\n", str_time(secs)); break;
+    case Duration_secs: if (soxi_total ==-1) printf("%f\n", secs); break;
     case Bits: printf("%u\n", ft->encoding.bits_per_sample); break;
+    case Bitrate: {
+      struct stat st;    /* ft->fp may validly be NULL, so stat not fstat */
+      if (!stat(filename, &st) && (st.st_mode & S_IFMT) == S_IFREG)
+        printf("%s\n", lsx_sigfigs3((size_t)(8. * st.st_size / secs + .5)));
+      else puts("0");
+      break;
+    }
     case Encoding: printf("%s\n", sox_encodings_info[ft->encoding.encoding].desc); break;
     case Annotation: if (ft->oob.comments) {
       sox_comments_t p = ft->oob.comments;
@@ -2253,9 +2271,10 @@
 
 static int soxi(int argc, char * const * argv)
 {
-  static char const opts[] = "trcsdbea?V::";
+  static char const opts[] = "trcsdDbBea?TV::";
   soxi_t type = Full;
   int opt, num_errors = 0;
+  sox_bool do_total = sox_false;
 
   while ((opt = getopt(argc, argv, opts)) > 0) /* act only on last option */
     if (opt == 'V') {
@@ -2271,13 +2290,36 @@
         }
         sox_globals.verbosity = (unsigned)i;
       }
-    } else type = 1 + (strchr(opts, opt) - opts);
-  if (type > Annotation)
-    printf("Usage: soxi [-V[level]] [-t|-r|-c|-s|-d|-b|-e|-a] infile1 ...\n");
-  else for (; optind < argc; ++optind) {
+    } 
+    else if (opt == 'T')
+      do_total = sox_true;
+    else type = 1 + (strchr(opts, opt) - opts);
+  if (type > Annotation) {
+    printf("Usage: soxi [-V[level]] [-T] [-t|-r|-c|-s|-d|-D|-b|-B|-e|-a] infile1 ...\n");
+    return -1;
+  }
+  if (type == Full)
+    do_total = sox_true;
+  else if (do_total && (type < Samples || type > Duration_secs)) {
+    fprintf(stderr, "soxi: ignoring -T; n/a with other given option");
+    do_total = sox_false;
+  }
+  soxi_total = -!do_total;
+  for (; optind < argc; ++optind) {
     if (sox_is_playlist(argv[optind]))
       num_errors += (sox_parse_playlist((sox_playlist_callback_t)soxi1, &type, argv[optind]) != SOX_SUCCESS);
     else num_errors += soxi1(&type, argv[optind]);
+  }
+  if (type == Full) {
+    if (soxi_file_count > 1 && soxi_total > 0)
+      printf("Total Duration of %u files: %s\n", soxi_file_count, str_time(soxi_total));
+  }
+  else if (do_total) {
+    if (soxi_total < 0)
+      puts("0");
+    else if (type == Duration)
+      printf("%s\n", str_time(soxi_total));
+    else printf("%f\n", soxi_total);
   }
   return num_errors;
 }