parent
faefb7e5b8
commit
b9c135a777
@ -1,382 +0,0 @@ |
|||||||
/* 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 = 0; |
|
||||||
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; |
|
||||||
} |
|
Loading…
Reference in new issue