Sigrid Solveig Haflínudóttirfix warnings6bc6a9b3 years agoHistory
382 lines · 11.8 KB · C
RawDownload
/* libSoX Yamaha TX-16W sampler file support * * May 20, 1993 * Copyright 1993 Rob Talley   (rob@aii.com) * This source code is freely redistributable and may be used for * any purpose. This copyright notice and the following copyright * notice must be maintained intact. No warranty whatsoever is * provided. This code is furnished AS-IS as a component of the * larger work Copyright 1991 Lance Norskog and Sundry Contributors. * Much appreciation to ross-c  for his sampConv utility for SGI/IRIX * from where these methods were derived. * * Jan 24, 1994 * Pat McElhatton, HP Media Technology Lab <patmc@apollo.hp.com> * Handles reading of files which do not have the sample rate field * set to one of the expected by looking at some other bytes in the * attack/loop length fields, and defaulting to 33kHz if the sample * rate is still unknown. * * January 12, 1995 * Copyright 1995 Mark Lakata (lakata@physics.berkeley.edu) * Additions to tx16w.c SOX handler.  This version writes as well as * reads TX16W format. * * July 31, 1998 * Cleaned up by Leigh Smith (leigh@psychokiller.dialix.oz.au) * for incorporation into the main sox distribution. * * September 24, 1998 * Forced output to mono signed words to match input.  It was basically * doing this anyways but now the user will see a display that it's been * overridden.  cbagwell@sprynet.com * */ #include "sox_i.h"#include <stdio.h>#include <string.h> #define TXMAXLEN 0x3FF80 /* Private data for TX16 file */typedef struct {  size_t   samples_out;  size_t   bytes_out;  size_t   rest;                 /* bytes remaining in sample file */  sox_sample_t odd;  sox_bool     odd_flag;} priv_t; struct WaveHeader_ {  char filetype[6]; /* = "LM8953", */  unsigned char    nulls[10],    dummy_aeg[6],    /* space for the AEG (never mind this) */    format,          /* 0x49 = looped, 0xC9 = non-looped */    sample_rate,     /* 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz */    atc_length[3],   /* I'll get to this... */    rpt_length[3],    unused[2];       /* set these to null, to be on the safe side */}; static const unsigned char magic1[4] = {0, 0x06, 0x10, 0xF6};static const unsigned char magic2[4] = {0, 0x52, 0x00, 0x52}; /* * 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){    int c;    char filetype[7];    int8_t format;    unsigned char sample_rate;    size_t num_samp_bytes = 0;    unsigned char gunk[8];    int blewIt;    uint8_t trash;     priv_t * sk = (priv_t *) ft->priv;    /* If you need to seek around the input file. */    if (! ft->seekable)    {        lsx_fail_errno(ft,SOX_EOF,"txw input file must be a file, not a pipe");        return(SOX_EOF);    }     /* This is dumb but portable, just count the bytes til EOF */    while (lsx_read_b_buf(ft, &trash, (size_t) 1) == 1)        num_samp_bytes++;    num_samp_bytes -= 32;         /* calculate num samples by sub header size */    lsx_seeki(ft, (off_t)0, 0);   /* rewind file */    sk->rest = num_samp_bytes;    /* set how many sample bytes to read */     /* first 6 bytes are file type ID LM8953 */    lsx_readchars(ft, filetype, sizeof(filetype) - 1);    filetype[6] = '\0';    for( c = 16; c > 0 ; c-- )    /* Discard next 16 bytes */        lsx_readb(ft, &trash);    lsx_readsb(ft, &format);    lsx_readb(ft, &sample_rate);    /*     * save next 8 bytes - if sample rate is 0, then we need     *  to look at gunk[2] and gunk[5] to get real rate     */    for( c = 0; c < 8; c++ )        lsx_readb(ft, &(gunk[c]));    /*     * We should now be pointing at start of raw sample data in file     */     /* Check to make sure we got a good filetype ID from file */    lsx_debug("Found header filetype %s",filetype);    if(strcmp(filetype,"LM8953"))    {        lsx_fail_errno(ft,SOX_EHDR,"Invalid filetype ID in input file header, != LM8953");        return(SOX_EOF);    }    /*     * Set up the sample rate as indicated by the header     */     switch( sample_rate ) {        case 1:            ft->signal.rate = 1e5 / 3;            break;        case 2:            ft->signal.rate = 1e5 / 2;            break;        case 3:            ft->signal.rate = 1e5 / 6;            break;        default:            blewIt = 1;            switch( gunk[2] & 0xFE ) {                case 0x06:                    if ( (gunk[5] & 0xFE) == 0x52 ) {                        blewIt = 0;                        ft->signal.rate = 1e5 / 3;                    }                    break;                case 0x10:                    if ( (gunk[5] & 0xFE) == 0x00 ) {                        blewIt = 0;                        ft->signal.rate = 1e5 / 2;                    }                    break;                case 0xF6:                    if ( (gunk[5] & 0xFE) == 0x52 ) {                        blewIt = 0;                        ft->signal.rate = 1e5 / 6;                    }                    break;            }            if ( blewIt ) {                lsx_debug("Invalid sample rate identifier found %d", sample_rate);                ft->signal.rate = 1e5 / 3;            }    }    lsx_debug("Sample rate = %g", ft->signal.rate);     ft->signal.channels = 1 ; /* not sure about stereo sample data yet ??? */    ft->encoding.bits_per_sample = 12;    ft->encoding.encoding = SOX_ENCODING_SIGN2;     return(SOX_SUCCESS);} /* * Read up to len samples from file. * Convert to sox_sample_t. * Place in buf[]. * Return number of samples read. */ static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len){    priv_t * sk = (priv_t *) ft->priv;    size_t done;    unsigned char uc1,uc2,uc3;    unsigned short s1,s2;     /*     * This gets called by the top level 'process' routine.     * We will essentially get called with a buffer pointer     * and a max length to read. Graciously, it is always     * an even amount so we don't have to worry about     * hanging onto the left over odd samples since there     * won't be any. Something to look out for though :-(     * We return the number of samples we read.     * We will get called over and over again until we return     *  0 bytes read.     */     /*     * This is ugly but it's readable!     * Read three bytes from stream, then decompose these into     * two unsigned short samples.     * TCC 3.0 appeared to do unwanted things, so we really specify     *  exactly what we want to happen.     * Convert unsigned short to sox_sample_t then shift up the result     *  so that the 12-bit sample lives in the most significant     *  12-bits of the sox_sample_t.     * This gets our two samples into the internal format which we     * deposit into the given buffer and adjust our counts respectivly.     */    for(done = 0; done < len; ) {        if(sk->rest < 3) break; /* Finished reading from file? */        lsx_readb(ft, &uc1);        lsx_readb(ft, &uc2);        lsx_readb(ft, &uc3);        sk->rest -= 3; /* adjust remaining for bytes we just read */        s1 = (unsigned short) (uc1 << 4) | (((uc2 >> 4) & 017));        s2 = (unsigned short) (uc3 << 4) | (( uc2 & 017 ));        *buf = (sox_sample_t) s1;        *buf = (*buf << 20);        buf++; /* sample one is done */        *buf = (sox_sample_t) s2;        *buf = (*buf << 20);        buf++; /* sample two is done */        done += 2; /* adjust converted & stored sample count */    }    return done;} static int startwrite(sox_format_t * ft){  priv_t * sk = (priv_t *) ft->priv;    struct WaveHeader_ WH;     lsx_debug("tx16w selected output");     memset(&WH, 0, sizeof(struct WaveHeader_));     /* If you have to seek around the output file */    if (! ft->seekable)    {        lsx_fail_errno(ft,SOX_EOF,"Output .txw file must be a file, not a pipe");        return(SOX_EOF);    }     /* dummy numbers, just for place holder, real header is written       at end of processing, since byte count is needed */     lsx_writebuf(ft, &WH, (size_t) 32);    sk->bytes_out = 32;    return(SOX_SUCCESS);} static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len0){  priv_t * sk = (priv_t *) ft->priv;  size_t last_i, i = 0, len = min(len0, TXMAXLEN - sk->samples_out);  sox_sample_t w1, w2;   while (i < len) {    last_i = i;    if (sk->odd_flag) {      w1 = sk->odd;      sk->odd_flag = sox_false;    }    else w1 = *buf++ >> 20, ++i;     if (i < len) {      w2 = *buf++ >> 20, ++i;      if (lsx_writesb(ft, (w1 >> 4) & 0xFF) ||          lsx_writesb(ft, (((w1 & 0x0F) << 4) | (w2 & 0x0F)) & 0xFF) ||          lsx_writesb(ft, (w2 >> 4) & 0xFF)) {        i = last_i;        break;      }      sk->samples_out += 2;      sk->bytes_out += 3;    }    else {      sk->odd = w1;      sk->odd_flag = sox_true;    }  }  return i;} static int stopwrite(sox_format_t * ft){  priv_t * sk = (priv_t *) ft->priv;    struct WaveHeader_ WH;    int AttackLength, LoopLength, i;     if (sk->odd_flag) {      sox_sample_t pad = 0;      write_samples(ft, &pad, (size_t) 1);    }     /* All samples are already written out. */    /* If file header needs fixing up, for example it needs the */    /* the number of samples in a field, seek back and write them here. */     lsx_debug("tx16w:output finished");     memset(&WH, 0, sizeof(struct WaveHeader_));    memcpy(WH.filetype, "LM8953", 6);    for (i=0;i<10;i++) WH.nulls[i]=0;    for (i=0;i<6;i++)  WH.dummy_aeg[i]=0;    for (i=0;i<2;i++)  WH.unused[i]=0;    for (i=0;i<2;i++)  WH.dummy_aeg[i] = 0;    for (i=2;i<6;i++)  WH.dummy_aeg[i] = 0x7F;     WH.format = 0xC9;   /* loop off */     /* the actual sample rate is not that important ! */    if (ft->signal.rate < 24000)      WH.sample_rate = 3;    else if (ft->signal.rate < 41000) WH.sample_rate = 1;    else                            WH.sample_rate = 2;     if (sk->samples_out >= TXMAXLEN) {        lsx_warn("Sound too large for TX16W. Truncating, Loop Off");        AttackLength       = TXMAXLEN/2;        LoopLength         = TXMAXLEN/2;    }    else if (sk->samples_out >=TXMAXLEN/2) {        AttackLength       = TXMAXLEN/2;        LoopLength         = sk->samples_out - TXMAXLEN/2;        if (LoopLength < 0x40) {            LoopLength   +=0x40;            AttackLength -= 0x40;        }    }    else if (sk->samples_out >= 0x80) {        AttackLength                       = sk->samples_out -0x40;        LoopLength                         = 0x40;    }    else {        AttackLength                       = 0x40;        LoopLength                         = 0x40;        for(i=sk->samples_out;i<0x80;i++) {            lsx_writeb(ft, 0);            lsx_writeb(ft, 0);            lsx_writeb(ft, 0);            sk->bytes_out += 3;        }    }     /* Fill up to 256 byte blocks; the TX16W seems to like that */     while ((sk->bytes_out % 0x100) != 0) {        lsx_writeb(ft, 0);        sk->bytes_out++;    }     WH.atc_length[0] = 0xFF & AttackLength;    WH.atc_length[1] = 0xFF & (AttackLength >> 8);    WH.atc_length[2] = (0x01 & (AttackLength >> 16)) +        magic1[WH.sample_rate];     WH.rpt_length[0] = 0xFF & LoopLength;    WH.rpt_length[1] = 0xFF & (LoopLength >> 8);    WH.rpt_length[2] = (0x01 & (LoopLength >> 16)) +        magic2[WH.sample_rate];     lsx_rewind(ft);    lsx_writebuf(ft, &WH, (size_t) 32);     return(SOX_SUCCESS);} LSX_FORMAT_HANDLER(txw){  static char const * const names[] = {"txw", NULL};  static sox_rate_t   const write_rates[] = {1e5/6, 1e5/3, 1e5/2, 0};  static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 12, 0, 0};  static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,    "Yamaha TX-16W sampler", names, SOX_FILE_MONO,    startread, read_samples, NULL,    startwrite, write_samples, stopwrite,    NULL, write_encodings, write_rates, 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