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