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;
}