1 /* libSoX Yamaha TX-16W sampler file support
2  *
3  * May 20, 1993
4  * Copyright 1993 Rob Talley   (rob@aii.com)
5  * This source code is freely redistributable and may be used for
6  * any purpose. This copyright notice and the following copyright
7  * notice must be maintained intact. No warranty whatsoever is
8  * provided. This code is furnished AS-IS as a component of the
9  * larger work Copyright 1991 Lance Norskog and Sundry Contributors.
10  * Much appreciation to ross-c  for his sampConv utility for SGI/IRIX
11  * from where these methods were derived.
12  *
13  * Jan 24, 1994
14  * Pat McElhatton, HP Media Technology Lab <patmc@apollo.hp.com>
15  * Handles reading of files which do not have the sample rate field
16  * set to one of the expected by looking at some other bytes in the
17  * attack/loop length fields, and defaulting to 33kHz if the sample
18  * rate is still unknown.
19  *
20  * January 12, 1995
21  * Copyright 1995 Mark Lakata (lakata@physics.berkeley.edu)
22  * Additions to tx16w.c SOX handler.  This version writes as well as
23  * reads TX16W format.
24  *
25  * July 31, 1998
26  * Cleaned up by Leigh Smith (leigh@psychokiller.dialix.oz.au)
27  * for incorporation into the main sox distribution.
28  *
29  * September 24, 1998
30  * Forced output to mono signed words to match input.  It was basically
31  * doing this anyways but now the user will see a display that it's been
32  * overridden.  cbagwell@sprynet.com
33  *
34  */
35 
36 #include "sox_i.h"
37 #include <stdio.h>
38 #include <string.h>
39 
40 #define TXMAXLEN 0x3FF80
41 
42 /* Private data for TX16 file */
43 typedef struct {
44   size_t   samples_out;
45   size_t   bytes_out;
46   size_t   rest;                 /* bytes remaining in sample file */
47   sox_sample_t odd;
48   sox_bool     odd_flag;
49 } priv_t;
50 
51 struct WaveHeader_ {
52   char filetype[6]; /* = "LM8953", */
53   unsigned char
54     nulls[10],
55     dummy_aeg[6],    /* space for the AEG (never mind this) */
56     format,          /* 0x49 = looped, 0xC9 = non-looped */
57     sample_rate,     /* 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz */
58     atc_length[3],   /* I'll get to this... */
59     rpt_length[3],
60     unused[2];       /* set these to null, to be on the safe side */
61 };
62 
63 static const unsigned char magic1[4] = {0, 0x06, 0x10, 0xF6};
64 static const unsigned char magic2[4] = {0, 0x52, 0x00, 0x52};
65 
66 /*
67  * Do anything required before you start reading samples.
68  * Read file header.
69  *      Find out sampling rate,
70  *      size and encoding of samples,
71  *      mono/stereo/quad.
72  */
startread(sox_format_t * ft)73 static int startread(sox_format_t * ft)
74 {
75     int c;
76     char filetype[7];
77     int8_t format;
78     unsigned char sample_rate;
79     size_t num_samp_bytes = 0;
80     unsigned char gunk[8];
81     int blewIt;
82     uint8_t trash;
83 
84     priv_t * sk = (priv_t *) ft->priv;
85     /* If you need to seek around the input file. */
86     if (! ft->seekable)
87     {
88         lsx_fail_errno(ft,SOX_EOF,"txw input file must be a file, not a pipe");
89         return(SOX_EOF);
90     }
91 
92     /* This is dumb but portable, just count the bytes til EOF */
93     while (lsx_read_b_buf(ft, &trash, (size_t) 1) == 1)
94         num_samp_bytes++;
95     num_samp_bytes -= 32;         /* calculate num samples by sub header size */
96     lsx_seeki(ft, (off_t)0, 0);   /* rewind file */
97     sk->rest = num_samp_bytes;    /* set how many sample bytes to read */
98 
99     /* first 6 bytes are file type ID LM8953 */
100     lsx_readchars(ft, filetype, sizeof(filetype) - 1);
101     filetype[6] = '\0';
102     for( c = 16; c > 0 ; c-- )    /* Discard next 16 bytes */
103         lsx_readb(ft, &trash);
104     lsx_readsb(ft, &format);
105     lsx_readb(ft, &sample_rate);
106     /*
107      * save next 8 bytes - if sample rate is 0, then we need
108      *  to look at gunk[2] and gunk[5] to get real rate
109      */
110     for( c = 0; c < 8; c++ )
111         lsx_readb(ft, &(gunk[c]));
112     /*
113      * We should now be pointing at start of raw sample data in file
114      */
115 
116     /* Check to make sure we got a good filetype ID from file */
117     lsx_debug("Found header filetype %s",filetype);
118     if(strcmp(filetype,"LM8953"))
119     {
120         lsx_fail_errno(ft,SOX_EHDR,"Invalid filetype ID in input file header, != LM8953");
121         return(SOX_EOF);
122     }
123     /*
124      * Set up the sample rate as indicated by the header
125      */
126 
127     switch( sample_rate ) {
128         case 1:
129             ft->signal.rate = 1e5 / 3;
130             break;
131         case 2:
132             ft->signal.rate = 1e5 / 2;
133             break;
134         case 3:
135             ft->signal.rate = 1e5 / 6;
136             break;
137         default:
138             blewIt = 1;
139             switch( gunk[2] & 0xFE ) {
140                 case 0x06:
141                     if ( (gunk[5] & 0xFE) == 0x52 ) {
142                         blewIt = 0;
143                         ft->signal.rate = 1e5 / 3;
144                     }
145                     break;
146                 case 0x10:
147                     if ( (gunk[5] & 0xFE) == 0x00 ) {
148                         blewIt = 0;
149                         ft->signal.rate = 1e5 / 2;
150                     }
151                     break;
152                 case 0xF6:
153                     if ( (gunk[5] & 0xFE) == 0x52 ) {
154                         blewIt = 0;
155                         ft->signal.rate = 1e5 / 6;
156                     }
157                     break;
158             }
159             if ( blewIt ) {
160                 lsx_debug("Invalid sample rate identifier found %d", sample_rate);
161                 ft->signal.rate = 1e5 / 3;
162             }
163     }
164     lsx_debug("Sample rate = %g", ft->signal.rate);
165 
166     ft->signal.channels = 1 ; /* not sure about stereo sample data yet ??? */
167     ft->encoding.bits_per_sample = 12;
168     ft->encoding.encoding = SOX_ENCODING_SIGN2;
169 
170     return(SOX_SUCCESS);
171 }
172 
173 /*
174  * Read up to len samples from file.
175  * Convert to sox_sample_t.
176  * Place in buf[].
177  * Return number of samples read.
178  */
179 
read_samples(sox_format_t * ft,sox_sample_t * buf,size_t len)180 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
181 {
182     priv_t * sk = (priv_t *) ft->priv;
183     size_t done = 0;
184     unsigned char uc1,uc2,uc3;
185     unsigned short s1,s2;
186 
187     /*
188      * This gets called by the top level 'process' routine.
189      * We will essentially get called with a buffer pointer
190      * and a max length to read. Graciously, it is always
191      * an even amount so we don't have to worry about
192      * hanging onto the left over odd samples since there
193      * won't be any. Something to look out for though :-(
194      * We return the number of samples we read.
195      * We will get called over and over again until we return
196      *  0 bytes read.
197      */
198 
199     /*
200      * This is ugly but it's readable!
201      * Read three bytes from stream, then decompose these into
202      * two unsigned short samples.
203      * TCC 3.0 appeared to do unwanted things, so we really specify
204      *  exactly what we want to happen.
205      * Convert unsigned short to sox_sample_t then shift up the result
206      *  so that the 12-bit sample lives in the most significant
207      *  12-bits of the sox_sample_t.
208      * This gets our two samples into the internal format which we
209      * deposit into the given buffer and adjust our counts respectivly.
210      */
211     for(done = 0; done < len; ) {
212         if(sk->rest < 3) break; /* Finished reading from file? */
213         lsx_readb(ft, &uc1);
214         lsx_readb(ft, &uc2);
215         lsx_readb(ft, &uc3);
216         sk->rest -= 3; /* adjust remaining for bytes we just read */
217         s1 = (unsigned short) (uc1 << 4) | (((uc2 >> 4) & 017));
218         s2 = (unsigned short) (uc3 << 4) | (( uc2 & 017 ));
219         *buf = (sox_sample_t) s1;
220         *buf = (*buf << 20);
221         buf++; /* sample one is done */
222         *buf = (sox_sample_t) s2;
223         *buf = (*buf << 20);
224         buf++; /* sample two is done */
225         done += 2; /* adjust converted & stored sample count */
226     }
227     return done;
228 }
229 
startwrite(sox_format_t * ft)230 static int startwrite(sox_format_t * ft)
231 {
232   priv_t * sk = (priv_t *) ft->priv;
233     struct WaveHeader_ WH;
234 
235     lsx_debug("tx16w selected output");
236 
237     memset(&WH, 0, sizeof(struct WaveHeader_));
238 
239     /* If you have to seek around the output file */
240     if (! ft->seekable)
241     {
242         lsx_fail_errno(ft,SOX_EOF,"Output .txw file must be a file, not a pipe");
243         return(SOX_EOF);
244     }
245 
246     /* dummy numbers, just for place holder, real header is written
247        at end of processing, since byte count is needed */
248 
249     lsx_writebuf(ft, &WH, (size_t) 32);
250     sk->bytes_out = 32;
251     return(SOX_SUCCESS);
252 }
253 
write_samples(sox_format_t * ft,const sox_sample_t * buf,size_t len0)254 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len0)
255 {
256   priv_t * sk = (priv_t *) ft->priv;
257   size_t last_i, i = 0, len = min(len0, TXMAXLEN - sk->samples_out);
258   sox_sample_t w1, w2;
259 
260   while (i < len) {
261     last_i = i;
262     if (sk->odd_flag) {
263       w1 = sk->odd;
264       sk->odd_flag = sox_false;
265     }
266     else w1 = *buf++ >> 20, ++i;
267 
268     if (i < len) {
269       w2 = *buf++ >> 20, ++i;
270       if (lsx_writesb(ft, (w1 >> 4) & 0xFF) ||
271           lsx_writesb(ft, (((w1 & 0x0F) << 4) | (w2 & 0x0F)) & 0xFF) ||
272           lsx_writesb(ft, (w2 >> 4) & 0xFF)) {
273         i = last_i;
274         break;
275       }
276       sk->samples_out += 2;
277       sk->bytes_out += 3;
278     }
279     else {
280       sk->odd = w1;
281       sk->odd_flag = sox_true;
282     }
283   }
284   return i;
285 }
286 
stopwrite(sox_format_t * ft)287 static int stopwrite(sox_format_t * ft)
288 {
289   priv_t * sk = (priv_t *) ft->priv;
290     struct WaveHeader_ WH;
291     int AttackLength, LoopLength, i;
292 
293     if (sk->odd_flag) {
294       sox_sample_t pad = 0;
295       write_samples(ft, &pad, (size_t) 1);
296     }
297 
298     /* All samples are already written out. */
299     /* If file header needs fixing up, for example it needs the */
300     /* the number of samples in a field, seek back and write them here. */
301 
302     lsx_debug("tx16w:output finished");
303 
304     memset(&WH, 0, sizeof(struct WaveHeader_));
305     strncpy(WH.filetype,"LM8953",(size_t)6);
306     for (i=0;i<10;i++) WH.nulls[i]=0;
307     for (i=0;i<6;i++)  WH.dummy_aeg[i]=0;
308     for (i=0;i<2;i++)  WH.unused[i]=0;
309     for (i=0;i<2;i++)  WH.dummy_aeg[i] = 0;
310     for (i=2;i<6;i++)  WH.dummy_aeg[i] = 0x7F;
311 
312     WH.format = 0xC9;   /* loop off */
313 
314     /* the actual sample rate is not that important ! */
315     if (ft->signal.rate < 24000)      WH.sample_rate = 3;
316     else if (ft->signal.rate < 41000) WH.sample_rate = 1;
317     else                            WH.sample_rate = 2;
318 
319     if (sk->samples_out >= TXMAXLEN) {
320         lsx_warn("Sound too large for TX16W. Truncating, Loop Off");
321         AttackLength       = TXMAXLEN/2;
322         LoopLength         = TXMAXLEN/2;
323     }
324     else if (sk->samples_out >=TXMAXLEN/2) {
325         AttackLength       = TXMAXLEN/2;
326         LoopLength         = sk->samples_out - TXMAXLEN/2;
327         if (LoopLength < 0x40) {
328             LoopLength   +=0x40;
329             AttackLength -= 0x40;
330         }
331     }
332     else if (sk->samples_out >= 0x80) {
333         AttackLength                       = sk->samples_out -0x40;
334         LoopLength                         = 0x40;
335     }
336     else {
337         AttackLength                       = 0x40;
338         LoopLength                         = 0x40;
339         for(i=sk->samples_out;i<0x80;i++) {
340             lsx_writeb(ft, 0);
341             lsx_writeb(ft, 0);
342             lsx_writeb(ft, 0);
343             sk->bytes_out += 3;
344         }
345     }
346 
347     /* Fill up to 256 byte blocks; the TX16W seems to like that */
348 
349     while ((sk->bytes_out % 0x100) != 0) {
350         lsx_writeb(ft, 0);
351         sk->bytes_out++;
352     }
353 
354     WH.atc_length[0] = 0xFF & AttackLength;
355     WH.atc_length[1] = 0xFF & (AttackLength >> 8);
356     WH.atc_length[2] = (0x01 & (AttackLength >> 16)) +
357         magic1[WH.sample_rate];
358 
359     WH.rpt_length[0] = 0xFF & LoopLength;
360     WH.rpt_length[1] = 0xFF & (LoopLength >> 8);
361     WH.rpt_length[2] = (0x01 & (LoopLength >> 16)) +
362         magic2[WH.sample_rate];
363 
364     lsx_rewind(ft);
365     lsx_writebuf(ft, &WH, (size_t) 32);
366 
367     return(SOX_SUCCESS);
368 }
369 
LSX_FORMAT_HANDLER(txw)370 LSX_FORMAT_HANDLER(txw)
371 {
372   static char const * const names[] = {"txw", NULL};
373   static sox_rate_t   const write_rates[] = {1e5/6, 1e5/3, 1e5/2, 0};
374   static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 12, 0, 0};
375   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
376     "Yamaha TX-16W sampler", names, SOX_FILE_MONO,
377     startread, read_samples, NULL,
378     startwrite, write_samples, stopwrite,
379     NULL, write_encodings, write_rates, sizeof(priv_t)
380   };
381   return &handler;
382 }
383