ref: 210336f9b78b4089163bc16804a1e76984c6c46d
dir: /src/sphere.c/
/* * NIST Sphere file format handler. */ /* * August 7, 2000 * * Copyright (C) 2000 Chris Bagwell (cbagwell@sprynet.com) * */ #include "st_i.h" #include <math.h> #include <string.h> #ifdef HAVE_ERRNO_H #include <errno.h> #endif /* Private data for SKEL file */ typedef struct spherestuff { char shorten_check[4]; st_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. */ int st_spherestartread(ft_t ft) { sphere_t sphere = (sphere_t) ft->priv; int rc; char *buf; char fldname[64], fldtype[16], fldsval[128]; int i; int header_size, bytes_read; long rate; /* Needed for rawread() */ rc = st_rawstartread(ft); if (rc) return rc; /* Magic header */ if (st_reads(ft, fldname, 8) == ST_EOF || strncmp(fldname, "NIST_1A", 7) != 0) { st_fail_errno(ft,ST_EHDR,"Sphere header does not begin with magic mord 'NIST_1A'"); return(ST_EOF); } if (st_reads(ft, fldsval, 8) == ST_EOF) { st_fail_errno(ft,ST_EHDR,"Error reading Sphere header"); return(ST_EOF); } /* Determine header size, and allocate a buffer large enough to hold it. */ sscanf(fldsval, "%d", &header_size); buf = (char *)malloc(header_size); if (buf == NULL) { st_fail_errno(ft,ST_ENOMEM,"Unable to allocate memory"); return(ST_ENOMEM); } /* Skip what we have read so far */ header_size -= 16; if (st_reads(ft, buf, header_size) == ST_EOF) { st_fail_errno(ft,ST_EHDR,"Error reading Sphere header"); free(buf); return(ST_EOF); } header_size -= (strlen(buf) + 1); while (strncmp(buf, "end_head", 8) != 0) { if (strncmp(buf, "sample_n_bytes", 14) == 0 && ft->info.size == -1) { sscanf(buf, "%63s %15s %d", fldname, fldtype, &i); ft->info.size = i; } if (strncmp(buf, "channel_count", 13) == 0 && ft->info.channels == -1) { sscanf(buf, "%63s %15s %d", fldname, fldtype, &i); ft->info.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->info.encoding == -1 && strncmp(fldsval,"ulaw",4) == 0) { ft->info.encoding = ST_ENCODING_ULAW; } } if (strncmp(buf, "sample_rate ", 12) == 0 && ft->info.rate == 0) { sscanf(buf, "%53s %15s %ld", fldname, fldtype, &rate); ft->info.rate = rate; } if (strncmp(buf, "sample_byte_format", 18) == 0) { sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval); if (strncmp(fldsval,"01",2) == 0) { /* Data is in little endian. */ if (ST_IS_BIGENDIAN) { ft->swap = ft->swap ? 0 : 1; } } else if (strncmp(fldsval,"10",2) == 0) { /* Data is in big endian. */ if (ST_IS_LITTLEENDIAN) { ft->swap = ft->swap ? 0 : 1; } } } if (st_reads(ft, buf, header_size) == ST_EOF) { st_fail_errno(ft,ST_EHDR,"Error reading Sphere header"); free(buf); return(ST_EOF); } header_size -= (strlen(buf) + 1); } if (ft->info.size == -1) ft->info.size = ST_SIZE_BYTE; /* sample_coding is optional and is PCM if missing. * This means encoding is signed if size = word or * unsigned if size = byte. */ if (ft->info.encoding == -1) { if (ft->info.size == 1) ft->info.encoding = ST_ENCODING_UNSIGNED; else ft->info.encoding = ST_ENCODING_SIGN2; } while (header_size) { bytes_read = st_readbuf(ft, buf, ST_SIZE_BYTE, header_size); if (bytes_read == 0) { free(buf); return(ST_EOF); } header_size -= bytes_read; } sphere->shorten_check[0] = 0; /* Check first four bytes of data to see if it's shorten * compressed or not. */ st_reads(ft, sphere->shorten_check, 4); if (!strcmp(sphere->shorten_check,"ajkg")) { st_fail_errno(ft,ST_EFMT,"File uses shorten compression, cannot handle this."); free(buf); return(ST_EOF); } free(buf); return (ST_SUCCESS); } /* * Read up to len samples from file. * Convert to signed longs. * Place in buf[]. * Return number of samples read. */ st_ssize_t st_sphereread(ft_t ft, st_sample_t *buf, st_ssize_t len) { sphere_t sphere = (sphere_t) ft->priv; if (sphere->shorten_check[0]) { /* TODO: put these 4 bytes into the buffer. Requires * knowing how to process ulaw and all version of PCM data size. */ sphere->shorten_check[0] = 0; } return st_rawread(ft, buf, len); } int st_spherestartwrite(ft_t ft) { int rc; int x; sphere_t sphere = (sphere_t) ft->priv; if (!ft->seekable) { st_fail_errno(ft,ST_EOF,"File must be seekable for sphere file output"); return (ST_EOF); } switch (ft->info.encoding) { case ST_ENCODING_ULAW: case ST_ENCODING_SIGN2: case ST_ENCODING_UNSIGNED: break; default: st_fail_errno(ft,ST_EFMT,"SPHERE format only supports ulaw and PCM data."); return(ST_EOF); } sphere->numSamples = 0; /* Needed for rawwrite */ rc = st_rawstartwrite(ft); if (rc) return rc; for (x = 0; x < 1024; x++) { st_writeb(ft, ' '); } return(ST_SUCCESS); } st_ssize_t st_spherewrite(ft_t ft, const st_sample_t *buf, st_ssize_t len) { sphere_t sphere = (sphere_t) ft->priv; sphere->numSamples += len; /* must later be divided by channels */ return st_rawwrite(ft, buf, len); } int st_spherestopwrite(ft_t ft) { int rc; char buf[128]; sphere_t sphere = (sphere_t) ft->priv; long samples, rate; rc = st_rawstopwrite(ft); if (rc) return rc; if (st_seeki(ft, 0L, 0) != 0) { st_fail_errno(ft,errno,"Could not rewird output file to rewrite sphere header."); return (ST_EOF); } st_writes(ft, "NIST_1A\n"); st_writes(ft, " 1024\n"); samples = sphere->numSamples/ft->info.channels; sprintf(buf, "sample_count -i %ld\n", samples); st_writes(ft, buf); sprintf(buf, "sample_n_bytes -i %d\n", ft->info.size); st_writes(ft, buf); sprintf(buf, "channel_count -i %d\n", ft->info.channels); st_writes(ft, buf); if (ft->swap) { sprintf(buf, "sample_byte_format -s2 %s\n", ST_IS_BIGENDIAN ? "01" : "10"); } else { sprintf(buf, "sample_byte_format -s2 %s\n", ST_IS_BIGENDIAN ? "10" : "01"); } st_writes(ft, buf); rate = ft->info.rate; sprintf(buf, "sample_rate -i %ld\n", rate); st_writes(ft, buf); if (ft->info.encoding == ST_ENCODING_ULAW) st_writes(ft, "sample_coding -s4 ulaw\n"); else st_writes(ft, "sample_coding -s3 pcm\n"); st_writes(ft, "end_head\n"); return (ST_SUCCESS); } /* NIST Sphere File */ static const char *spherenames[] = { "sph", NULL }; static st_format_t st_sphere_format = { spherenames, NULL, ST_FILE_STEREO, st_spherestartread, st_sphereread, st_rawstopread, st_spherestartwrite, st_spherewrite, st_spherestopwrite, st_format_nothing_seek }; const st_format_t *st_sphere_format_fn(void) { return &st_sphere_format; }