ref: c94b05ceb57399f55ddd31c51748bb5bf2f7835c
dir: /src/sphere.c/
/* * NIST Sphere file format handler. * * August 7, 2000 * * Copyright (C) 2000 Chris Bagwell (cbagwell@sprynet.com) * */ #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) { 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; /* 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); } if (sox_reads(ft, fldsval, 8) == SOX_EOF) { 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); /* 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); } 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. */ } 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); } if (!ft->encoding.bits_per_sample) ft->encoding.bits_per_sample = 8; /* 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; } 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); } sphere->numSamples = 0; /* Needed for rawwrite */ rc = sox_rawstartwrite(ft); if (rc) return rc; for (x = 0; x < 1024; x++) { sox_writeb(ft, ' '); } return(SOX_SUCCESS); } static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len) { sphere_t sphere = (sphere_t) ft->priv; sphere->numSamples += len; /* must later be divided by channels */ return sox_rawwrite(ft, buf, len); } 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; 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, "channel_count -i %d\n", ft->signal.channels); sox_writes(ft, buf); sprintf(buf, "sample_byte_format -s2 %s\n", 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); 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"); return (SOX_SUCCESS); } SOX_FORMAT_HANDLER(sphere) { 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_ULAW, 8, 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 }; return &handler; }