342 lines · 11.9 KB · C
RawDownload
/* Amiga 8SVX format handler: W V Neisius, February 1992 */ #include "sox_i.h" #include <errno.h>#include <string.h>#include <stdlib.h>#include <stdio.h> #define BUFLEN 512 /* Private data used by writer */typedef struct{  uint32_t nsamples;  uint32_t left;  off_t ch0_pos;  sox_uint8_t buf[4][BUFLEN];  FILE* tmp[4];} priv_t; static void svxwriteheader(sox_format_t *, size_t); /*======================================================================*//*                         8SVXSTARTREAD                                *//*======================================================================*/ static int startread(sox_format_t * ft){        priv_t * p = (priv_t * ) ft->priv;         char buf[12];        char *chunk_buf;         uint32_t totalsize;        uint32_t chunksize;         uint32_t channels;        unsigned short rate;         if (! ft->seekable)        {                lsx_fail_errno(ft,SOX_EINVAL,"8svx input file must be a file, not a pipe");                return (SOX_EOF);        }        rate = 0;        channels = 1;         /* read FORM chunk */        if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0)        {                lsx_fail_errno(ft, SOX_EHDR, "Header did not begin with magic word `FORM'");                return(SOX_EOF);        }        lsx_readdw(ft, &totalsize);        if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "8SVX", (size_t)4) != 0)        {                lsx_fail_errno(ft, SOX_EHDR, "'FORM' chunk does not specify `8SVX' as type");                return(SOX_EOF);        }         /* read chunks until 'BODY' (or end) */        while (lsx_reads(ft, buf, (size_t)4) == SOX_SUCCESS && strncmp(buf,"BODY",(size_t)4) != 0) {                if (strncmp(buf,"VHDR",(size_t)4) == 0) {                        lsx_readdw(ft, &chunksize);                        if (chunksize != 20)                        {                                lsx_fail_errno(ft, SOX_EHDR, "VHDR chunk has bad size");                                return(SOX_EOF);                        }                        lsx_seeki(ft,(off_t)12,SEEK_CUR);                        lsx_readw(ft, &rate);                        lsx_seeki(ft,(off_t)1,SEEK_CUR);                        lsx_readbuf(ft, buf,(size_t)1);                        if (buf[0] != 0)                        {                                lsx_fail_errno(ft, SOX_EFMT, "Unsupported data compression");                                return(SOX_EOF);                        }                        lsx_seeki(ft,(off_t)4,SEEK_CUR);                        continue;                }                 if (strncmp(buf,"ANNO",(size_t)4) == 0) {                        lsx_readdw(ft, &chunksize);                        if (chunksize & 1)                                chunksize++;                        chunk_buf = lsx_malloc(chunksize + (size_t)2);                        if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize)                                        != chunksize)                        {                                lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");                                return(SOX_EOF);                        }                        chunk_buf[chunksize] = '\0';                        lsx_debug("%s",chunk_buf);                        free(chunk_buf);                         continue;                }                 if (strncmp(buf,"NAME",(size_t)4) == 0) {                        lsx_readdw(ft, &chunksize);                        if (chunksize & 1)                                chunksize++;                        chunk_buf = lsx_malloc(chunksize + (size_t)1);                        if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize)                                        != chunksize)                        {                                lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");                                return(SOX_EOF);                        }                        chunk_buf[chunksize] = '\0';                        lsx_debug("%s",chunk_buf);                        free(chunk_buf);                         continue;                }                 if (strncmp(buf,"CHAN",(size_t)4) == 0) {                        lsx_readdw(ft, &chunksize);                        if (chunksize != 4)                        {                                lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header");                                return(SOX_EOF);                        }                        lsx_readdw(ft, &channels);                        channels = (channels & 0x01) +                                        ((channels & 0x02) >> 1) +                                        ((channels & 0x04) >> 2) +                                        ((channels & 0x08) >> 3);                         continue;                }                 /* some other kind of chunk */                lsx_readdw(ft, &chunksize);                if (chunksize & 1)                        chunksize++;                lsx_seeki(ft,(off_t)chunksize,SEEK_CUR);                continue;         }         if (rate == 0)        {                lsx_fail_errno(ft, SOX_EHDR, "Invalid sample rate");                return(SOX_EOF);        }        if (strncmp(buf,"BODY",(size_t)4) != 0)        {                lsx_fail_errno(ft, SOX_EHDR, "BODY chunk not found");                return(SOX_EOF);        }        lsx_readdw(ft, &(p->nsamples));        p->left = p->nsamples;        p->ch0_pos = lsx_tell(ft);         ft->signal.length = p->nsamples;        ft->signal.channels = channels;        ft->signal.rate = rate;        ft->encoding.encoding = SOX_ENCODING_SIGN2;        ft->encoding.bits_per_sample = 8;         return(SOX_SUCCESS);} /*======================================================================*//*                         8SVXREAD                                     *//*======================================================================*/static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t nsamp){    size_t done = 0;     priv_t * p = (priv_t * ) ft->priv;    size_t frames = nsamp / ft->signal.channels;    unsigned width = p->nsamples / ft->signal.channels;     if (p->left < frames)        frames = p->left;     while (done != frames) {        size_t chunk = frames - done;        size_t i;        unsigned ch;         if (chunk > BUFLEN)            chunk = BUFLEN;         for (ch = 0; ch != ft->signal.channels; ch++) {            if (lsx_seeki(ft, p->ch0_pos + ch * width, SEEK_SET) ||                chunk != lsx_readbuf(ft, p->buf[ch], chunk))                return done * ft->signal.channels;        }         for (i = 0; i != chunk; i++) {            for (ch = 0; ch != ft->signal.channels; ch++) {                /* scale signed up to long's range */                *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(p->buf[ch][i], dummy);            }        }         done += chunk;        p->left -= chunk * ft->signal.channels;        p->ch0_pos += chunk;    }    return done * ft->signal.channels;} /*======================================================================*//*                         8SVXSTARTWRITE                               *//*======================================================================*/static int startwrite(sox_format_t * ft){        priv_t * p = (priv_t * ) ft->priv;        size_t i;         /* open channel output files */        for (i = 0; i < ft->signal.channels; i++) {                if ((p->tmp[i] = lsx_tmpfile()) == NULL)                {                        lsx_fail_errno(ft,errno,"Can't open channel output file");                        return(SOX_EOF);                }        }         p->nsamples = 0;        return(SOX_SUCCESS);} /*======================================================================*//*                         8SVXWRITE                                    *//*======================================================================*/ static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len){        priv_t * p = (priv_t * ) ft->priv;        SOX_SAMPLE_LOCALS;         unsigned char datum;        size_t done = 0, i;         p->nsamples += len;         while(done < len) {                for (i = 0; i < ft->signal.channels; i++) {                        datum = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips);                        putc(datum, p->tmp[i]);                }                done += ft->signal.channels;        }        return (done);} /*======================================================================*//*                         8SVXSTOPWRITE                                *//*======================================================================*/ static int stopwrite(sox_format_t * ft){        priv_t * p = (priv_t * ) ft->priv;         size_t i, len;        char svxbuf[512];         svxwriteheader(ft, (size_t) p->nsamples);         /* append all channel pieces to channel 0 */        /* close temp files */        for (i = 0; i < ft->signal.channels; i++) {                if (fseeko(p->tmp[i], (off_t)0, 0))                {                        lsx_fail_errno (ft,errno,"Can't rewind channel output file %lu",(unsigned long)i);                        return(SOX_EOF);                }                while (!feof(p->tmp[i])) {                        len = fread(svxbuf, (size_t) 1, (size_t) 512, p->tmp[i]);                        if (lsx_writebuf(ft, svxbuf, len) != len) {                          lsx_fail_errno (ft,errno,"Can't write channel output file %lu",(unsigned long)i);                          return SOX_EOF;                        }                }                fclose (p->tmp[i]);        }         /* add a pad byte if BODY size is odd */        if(p->nsamples % 2 != 0)            lsx_writeb(ft, '\0');         return(SOX_SUCCESS);} /*======================================================================*//*                         8SVXWRITEHEADER                              *//*======================================================================*/#define SVXHEADERSIZE 100static void svxwriteheader(sox_format_t * ft, size_t nsamples){        size_t formsize =  nsamples + SVXHEADERSIZE - 8;         /* FORM size must be even */        if(formsize % 2 != 0) formsize++;         lsx_writes(ft, "FORM");        lsx_writedw(ft, (unsigned) formsize);  /* size of file */        lsx_writes(ft, "8SVX"); /* File type */         lsx_writes(ft, "VHDR");        lsx_writedw(ft, 20); /* number of bytes to follow */        lsx_writedw(ft, (unsigned) nsamples/ft->signal.channels);  /* samples, 1-shot */        lsx_writedw(ft, 0);  /* samples, repeat */        lsx_writedw(ft, 0);  /* samples per repeat cycle */        lsx_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5)));        lsx_writeb(ft,1); /* number of octabes */        lsx_writeb(ft,0); /* data compression (none) */        lsx_writew(ft,1); lsx_writew(ft,0); /* volume */         lsx_writes(ft, "ANNO");        lsx_writedw(ft, 32); /* length of block */        lsx_writes(ft, "File created by Sound Exchange  ");         lsx_writes(ft, "CHAN");        lsx_writedw(ft, 4);        lsx_writedw(ft, (ft->signal.channels == 2) ? 6u :                   (ft->signal.channels == 4) ? 15u : 2u);         lsx_writes(ft, "BODY");        lsx_writedw(ft, (unsigned) nsamples); /* samples in file */} LSX_FORMAT_HANDLER(svx){  static char const * const names[] = {"8svx", NULL};  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 8, 0, 0};  static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,    "Amiga audio format (a subformat of the Interchange File Format)",    names, SOX_FILE_BIG_END|SOX_FILE_MONO|SOX_FILE_STEREO|SOX_FILE_QUAD,    startread, read_samples, NULL,    startwrite, write_samples, stopwrite,    NULL, write_encodings, NULL, sizeof(priv_t)  };  return &handler;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t