shithub: sox

Download patch

ref: 23f04e2fb1b7937a99003d1dad6f6dd8fea15028
parent: 09794bf2047812a11db1bfba9b1910de5eada761
author: robs <robs>
date: Sun Mar 16 11:13:51 EDT 2008

sphere updates

--- a/src/misc.c
+++ b/src/misc.c
@@ -141,19 +141,19 @@
     ft->data_start = sox_tell(ft);
 
   if (channels && ft->signal.channels && ft->signal.channels != channels)
-    sox_warn("'%s': overriding number of channels", ft->filename);
+    sox_warn("`%s': overriding number of channels", ft->filename);
   else ft->signal.channels = channels;
 
   if (rate && ft->signal.rate && ft->signal.rate != rate)
-    sox_warn("'%s': overriding sample rate", ft->filename);
+    sox_warn("`%s': overriding sample rate", ft->filename);
   else ft->signal.rate = rate;
 
   if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding)
-    sox_warn("'%s': overriding encoding type", ft->filename);
+    sox_warn("`%s': overriding encoding type", ft->filename);
   else ft->encoding.encoding = encoding;
 
   if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample)
-    sox_warn("'%s': overriding encoding size", ft->filename);
+    sox_warn("`%s': overriding encoding size", ft->filename);
   ft->encoding.bits_per_sample = bits_per_sample;
 
   if (ft->encoding.bits_per_sample && sox_filelength(ft)) {
@@ -161,10 +161,10 @@
     if (!ft->length)
       ft->length = calculated_length;
     else if (length != calculated_length)
-      sox_warn("file header gives the total number of samples as %u but file length indicates the number is in fact %u", (unsigned)length, (unsigned)calculated_length); /* FIXME: casts */
+      sox_warn("`%s': file header gives the total number of samples as %u but file length indicates the number is in fact %u", ft->filename, (unsigned)length, (unsigned)calculated_length); /* FIXME: casts */
   }
 
-  if ( sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
+  if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
     return SOX_SUCCESS;
   sox_fail_errno(ft, EINVAL, "invalid format for this file type");
   return SOX_EOF;
@@ -214,6 +214,7 @@
   size_t ret = fread(buf, 1, len, ft->fp);
   if (ret != len && ferror(ft->fp))
     sox_fail_errno(ft, errno, "sox_readbuf");
+  ft->tell += ret;
   return ret;
 }
 
@@ -250,6 +251,7 @@
     sox_fail_errno(ft, errno, "error writing output file");
     clearerr(ft->fp); /* Allows us to seek back to write header */
   }
+  ft->tell += ret;
   return ret;
 }
 
@@ -268,7 +270,7 @@
 
 sox_ssize_t sox_tell(sox_format_t * ft)
 {
-  return (sox_ssize_t)ftello(ft->fp);
+  return ft->seekable? (sox_ssize_t)ftello(ft->fp) : ft->tell;
 }
 
 int sox_eof(sox_format_t * ft)
@@ -582,6 +584,7 @@
             while (offset > 0 && !feof(ft->fp)) {
                 getc(ft->fp);
                 offset--;
+                ++ft->tell;
             }
             if (offset)
                 sox_fail_errno(ft,SOX_EOF, "offset past EOF");
--- a/src/sox.h
+++ b/src/sox.h
@@ -336,6 +336,7 @@
   FILE             *fp;                  /* File stream pointer */
   int              sox_errno;            /* Failure error codes */
   char             sox_errstr[256];      /* Extend Failure text */
+  off_t            tell;
   off_t            data_start;
   sox_format_handler_t handler;  /* format struct for this file */
 };
--- a/src/sphere.c
+++ b/src/sphere.c
@@ -8,253 +8,179 @@
  */
 
 #include "sox_i.h"
-
-#include <math.h>
 #include <string.h>
-#include <errno.h>
 
-/* Private data for sphere file */
-typedef struct spherestuff {
-        char      shorten_check[4];
-        sox_size_t numSamples;
-} *sphere_t;
-
-/*
- * Do anything required before you start reading samples.
- * Read file header. 
- *      Find out sampling rate, 
- *      size and encoding of samples, 
- *      mono/stereo/quad.
- */
-static int startread(sox_format_t * ft) 
+static int start_read(sox_format_t * ft)
 {
-        sphere_t sphere = (sphere_t) ft->priv;
-        char *buf;
-        char fldname[64], fldtype[16], fldsval[128];
-        int i;
-        sox_size_t header_size, bytes_read;
-        long rate;
+  sox_encoding_t encoding = SOX_ENCODING_SIGN2;
+  sox_size_t     header_size, bytes_read;
+  sox_size_t     num_samples = 0;
+  unsigned       bytes_per_sample = 0;
+  unsigned       channels = 1;
+  unsigned       rate = 16000;
+  char           fldname[64], fldtype[16], fldsval[128];
+  char           * buf;
 
-        /* Magic header */
-        if (sox_reads(ft, fldname, 8) == SOX_EOF || strncmp(fldname, "NIST_1A", 7) != 0)
-        {
-            sox_fail_errno(ft,SOX_EHDR,"Sphere header does not begin with magic mord 'NIST_1A'");
-            return(SOX_EOF);
-        }
+  /* Magic header */
+  if (sox_reads(ft, fldname, 8) || strncmp(fldname, "NIST_1A", 7) != 0) {
+    sox_fail_errno(ft, SOX_EHDR, "Sphere header does not begin with magic word 'NIST_1A'");
+    return (SOX_EOF);
+  }
 
-        if (sox_reads(ft, fldsval, 8) == SOX_EOF)
-        {
-            sox_fail_errno(ft,SOX_EHDR,"Error reading Sphere header");
-            return(SOX_EOF);
-        }
+  if (sox_reads(ft, fldsval, 8)) {
+    sox_fail_errno(ft, SOX_EHDR, "Error reading Sphere header");
+    return (SOX_EOF);
+  }
 
-        /* Determine header size, and allocate a buffer large enough to hold it. */
-        sscanf(fldsval, "%u", &header_size);
-        buf = xmalloc(header_size);
+  /* Determine header size, and allocate a buffer large enough to hold it. */
+  sscanf(fldsval, "%u", &header_size);
+  buf = xmalloc(header_size);
 
-        /* Skip what we have read so far */
-        header_size -= 16;
+  /* Skip what we have read so far */
+  header_size -= 16;
 
-        if (sox_reads(ft, buf, header_size) == SOX_EOF)
-        {
-            sox_fail_errno(ft,SOX_EHDR,"Error reading Sphere header");
-            free(buf);
-            return(SOX_EOF);
-        }
+  if (sox_reads(ft, buf, header_size) == SOX_EOF) {
+    sox_fail_errno(ft, SOX_EHDR, "Error reading Sphere header");
+    free(buf);
+    return (SOX_EOF);
+  }
 
-        header_size -= (strlen(buf) + 1);
+  header_size -= (strlen(buf) + 1);
 
-        while (strncmp(buf, "end_head", 8) != 0)
-        {
-            if (strncmp(buf, "sample_n_bytes", 14) == 0 && !ft->encoding.bits_per_sample)
-            {
-                sscanf(buf, "%63s %15s %d", fldname, fldtype, &i);
-                ft->encoding.bits_per_sample = i << 3;
-            }
-            if (strncmp(buf, "channel_count", 13) == 0 && 
-                ft->signal.channels == 0)
-            {
-                sscanf(buf, "%63s %15s %d", fldname, fldtype, &i);
-                ft->signal.channels = i;
-            }
-            if (strncmp(buf, "sample_coding", 13) == 0)
-            {
-                sscanf(buf, "%63s %15s %127s", fldname, fldtype, fldsval);
-                /* Only bother looking for ulaw flag.  All others
-                 * should be caught below by default PCM check
-                 */
-                if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN && 
-                    strncmp(fldsval,"ulaw",4) == 0)
-                {
-                    ft->encoding.encoding = SOX_ENCODING_ULAW;
-                }
-            }
-            if (strncmp(buf, "sample_rate ", 12) == 0 &&
-                ft->signal.rate == 0)
-            {
-                sscanf(buf, "%53s %15s %ld", fldname, fldtype, &rate);
-                ft->signal.rate = rate;
-            }
-            if (strncmp(buf, "sample_byte_format", 18) == 0)
-            {
-                sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval);
-                if (strncmp(fldsval,"01",2) == 0)
-                  ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN; /* Data is little endian. */
-                else if (strncmp(fldsval,"10",2) == 0)
-                  ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN; /* Data is big endian. */
-            }
+  while (strncmp(buf, "end_head", 8) != 0) {
+    if (strncmp(buf, "sample_n_bytes", 14) == 0)
+      sscanf(buf, "%63s %15s %u", fldname, fldtype, &bytes_per_sample);
+    else if (strncmp(buf, "channel_count", 13) == 0)
+      sscanf(buf, "%63s %15s %u", fldname, fldtype, &channels);
+    else if (strncmp(buf, "sample_count ", 13) == 0)
+      sscanf(buf, "%53s %15s %u", fldname, fldtype, &num_samples);
+    else if (strncmp(buf, "sample_rate ", 12) == 0)
+      sscanf(buf, "%53s %15s %u", fldname, fldtype, &rate);
+    else if (strncmp(buf, "sample_coding", 13) == 0) {
+      sscanf(buf, "%63s %15s %127s", fldname, fldtype, fldsval);
+      if (!strcasecmp(fldsval, "ulaw") || !strcasecmp(fldsval, "mu-law"))
+        encoding = SOX_ENCODING_ULAW;
+      else if (!strcasecmp(fldsval, "pcm"))
+        encoding = SOX_ENCODING_SIGN2;
+      else {
+        sox_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval);
+        free(buf);
+        return SOX_EOF;
+      }
+    }
+    else if (strncmp(buf, "sample_byte_format", 18) == 0) {
+      sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval);
+      if (strcmp(fldsval, "01") == 0)         /* Data is little endian. */
+        ft->encoding.reverse_bytes = SOX_IS_BIGENDIAN;
+      else if (strcmp(fldsval, "10") == 0)    /* Data is big endian. */
+        ft->encoding.reverse_bytes = SOX_IS_LITTLEENDIAN;
+      else if (strcmp(fldsval, "1")) {
+        sox_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval);
+        free(buf);
+        return SOX_EOF;
+      }
+    }
 
-            if (sox_reads(ft, buf, header_size) == SOX_EOF)
-            {
-                sox_fail_errno(ft,SOX_EHDR,"Error reading Sphere header");
-                free(buf);
-                return(SOX_EOF);
-            }
+    if (sox_reads(ft, buf, header_size) == SOX_EOF) {
+      sox_fail_errno(ft, SOX_EHDR, "Error reading Sphere header");
+      free(buf);
+      return (SOX_EOF);
+    }
 
-            header_size -= (strlen(buf) + 1);
-        }
+    header_size -= (strlen(buf) + 1);
+  }
 
-        if (!ft->encoding.bits_per_sample)
-            ft->encoding.bits_per_sample = 8;
+  if (!bytes_per_sample)
+    bytes_per_sample = encoding == SOX_ENCODING_ULAW? 1 : 2;
 
-        /* sample_coding is optional and is PCM if missing.
-         * This means encoding is signed if size = word or
-         * unsigned if size = byte.
-         */
-        if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
-        {
-            if (ft->encoding.bits_per_sample == 8)
-                ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
-            else
-                ft->encoding.encoding = SOX_ENCODING_SIGN2;
-        }
+  if (encoding == SOX_ENCODING_SIGN2 && bytes_per_sample == 1)
+    ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
 
-        while (header_size)
-        {
-            bytes_read = sox_readbuf(ft, buf, header_size);
-            if (bytes_read == 0)
-            {
-                free(buf);
-                return(SOX_EOF);
-            }
-            header_size -= bytes_read;
-        }
-
-        sphere->shorten_check[0] = 0;
-
-        if (ft->seekable) {
-          /* Check first four bytes of data to see if it's shorten compressed. */
-          sox_ssize_t pos = sox_tell(ft);
-          sox_reads(ft, sphere->shorten_check, 4);
-
-          if (!strcmp(sphere->shorten_check,"ajkg")) {
-            sox_fail_errno(ft, SOX_EFMT, "File uses shorten compression, cannot handle this.");
-            free(buf);
-            return(SOX_EOF);
-          }
-
-          /* Can't just seek -4, as sox_reads has read 1-4 bytes */
-          sox_seeki(ft, pos, SEEK_SET); 
-        }
-
-        free(buf);
-        return sox_rawstartread(ft);
-}
-
-static int startwrite(sox_format_t * ft) 
-{
-    int rc;
-    int x;
-    sphere_t sphere = (sphere_t) ft->priv;
-
-    if (!ft->seekable)
-    {
-        sox_fail_errno(ft,SOX_EOF,"File must be seekable for sphere file output");
-        return (SOX_EOF);
+  while (header_size) {
+    bytes_read = sox_readbuf(ft, buf, header_size);
+    if (bytes_read == 0) {
+      free(buf);
+      return (SOX_EOF);
     }
+    header_size -= bytes_read;
+  }
+  free(buf);
 
-    sphere->numSamples = 0;
+  if (ft->seekable) {
+    /* Check first four bytes of data to see if it's shorten compressed. */
+    char           shorten_check[4];
 
-    /* Needed for rawwrite */
-    rc = sox_rawstartwrite(ft);
-    if (rc)
-        return rc;
+    if (sox_readchars(ft, shorten_check, sizeof(shorten_check)))
+      return SOX_EOF;
+    sox_seeki(ft, -(sox_ssize_t)sizeof(shorten_check), SEEK_CUR);
 
-    for (x = 0; x < 1024; x++)
-    {
-        sox_writeb(ft, ' ');
+    if (!memcmp(shorten_check, "ajkg", sizeof(shorten_check))) {
+      sox_fail_errno(ft, SOX_EFMT,
+                     "File uses shorten compression, cannot handle this.");
+      return (SOX_EOF);
     }
+  }
 
-    return(SOX_SUCCESS);
-        
+  return sox_check_read_params(ft, channels, (sox_rate_t)rate, encoding,
+      bytes_per_sample << 3, (off_t)(num_samples * channels));
 }
 
-static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) 
+static int write_header(sox_format_t * ft)
 {
-    sphere_t sphere = (sphere_t) ft->priv;
+  char buf[128];
+  long samples = (ft->olength ? ft->olength : ft->length) / ft->signal.channels;
 
-    sphere->numSamples += len; /* must later be divided by channels */
-    return sox_rawwrite(ft, buf, len);
-}
+  sox_writes(ft, "NIST_1A\n");
+  sox_writes(ft, "   1024\n");
 
-static int stopwrite(sox_format_t * ft) 
-{
-    char buf[128];
-    sphere_t sphere = (sphere_t) ft->priv;
-    long samples, rate;
-
-    if (sox_seeki(ft, 0, 0) != 0)
-    {
-        sox_fail_errno(ft,errno,"Could not rewind output file to rewrite sphere header.");
-        return (SOX_EOF);
-    }
-
-    sox_writes(ft, "NIST_1A\n");
-    sox_writes(ft, "   1024\n");
-
-    samples = sphere->numSamples/ft->signal.channels;
+  if (samples) {
     sprintf(buf, "sample_count -i %ld\n", samples);
     sox_writes(ft, buf);
+  }
 
-    sprintf(buf, "sample_n_bytes -i %d\n", ft->encoding.bits_per_sample >> 3);
-    sox_writes(ft, buf);
+  sprintf(buf, "sample_n_bytes -i %d\n", ft->encoding.bits_per_sample >> 3);
+  sox_writes(ft, buf);
 
-    sprintf(buf, "channel_count -i %d\n", ft->signal.channels);
-    sox_writes(ft, buf);
+  sprintf(buf, "channel_count -i %d\n", ft->signal.channels);
+  sox_writes(ft, buf);
 
+  if (ft->encoding.bits_per_sample == 8)
+    sprintf(buf, "sample_byte_format -s1 1\n");
+  else
     sprintf(buf, "sample_byte_format -s2 %s\n",
-        ft->encoding.reverse_bytes != SOX_IS_BIGENDIAN ? "10" : "01");
-    sox_writes(ft, buf);
+            ft->encoding.reverse_bytes != SOX_IS_BIGENDIAN ? "10" : "01");
+  sox_writes(ft, buf);
 
-    rate = ft->signal.rate;
-    sprintf(buf, "sample_rate -i %ld\n", rate);
-    sox_writes(ft, buf);
+  sprintf(buf, "sample_rate -i %u\n", (unsigned) (ft->signal.rate + .5));
+  sox_writes(ft, buf);
 
-    if (ft->encoding.encoding == SOX_ENCODING_ULAW)
-        sox_writes(ft, "sample_coding -s4 ulaw\n");
-    else
-        sox_writes(ft, "sample_coding -s3 pcm\n");
+  if (ft->encoding.encoding == SOX_ENCODING_ULAW)
+    sox_writes(ft, "sample_coding -s4 ulaw\n");
+  else
+    sox_writes(ft, "sample_coding -s3 pcm\n");
 
-    sox_writes(ft, "end_head\n");
+  sox_writes(ft, "end_head\n");
 
-    return (SOX_SUCCESS);
+  sox_padbytes(ft, 1024 - (sox_size_t)sox_tell(ft));
+  return SOX_SUCCESS;
 }
 
 SOX_FORMAT_HANDLER(sphere)
 {
-  static char const * const names[] = {"sph", "nist", NULL};
+  static char const *const names[] = { "sph", "nist", NULL };
   static unsigned const write_encodings[] = {
-    SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0,
-    SOX_ENCODING_UNSIGNED, 8, 16, 24, 32, 0,
+    SOX_ENCODING_SIGN2, 16, 24, 32, 0,
+    SOX_ENCODING_UNSIGNED, 8, 0,
     SOX_ENCODING_ULAW, 8, 0,
-    0};
+    0
+  };
   static sox_format_handler_t const handler = {
     SOX_LIB_VERSION_CODE,
     "SPeech HEader Resources; defined by NIST",
-    names, 0,
-    startread, sox_rawread, sox_rawstopread,
-    startwrite, write_samples, stopwrite,
-    NULL, write_encodings, NULL
+    names, SOX_FILE_REWIND,
+    start_read, sox_rawread, NULL,
+    write_header, sox_rawwrite, NULL,
+    sox_rawseek, write_encodings, NULL
   };
   return &handler;
 }