tx16w: silence compiler warning
[sox.git] / src / tx16w.c
blob42c644d543c2b700858629995527e30555c77cf1
1 /* libSoX Yamaha TX-16W sampler file support
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.
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.
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.
25 * July 31, 1998
26 * Cleaned up by Leigh Smith (leigh@psychokiller.dialix.oz.au)
27 * for incorporation into the main sox distribution.
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
36 #include "sox_i.h"
37 #include <stdio.h>
38 #include <string.h>
40 #define TXMAXLEN 0x3FF80
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;
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 */
63 static const unsigned char magic1[4] = {0, 0x06, 0x10, 0xF6};
64 static const unsigned char magic2[4] = {0, 0x52, 0x00, 0x52};
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.
73 static int startread(sox_format_t * ft)
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;
84 priv_t * sk = (priv_t *) ft->priv;
85 /* If you need to seek around the input file. */
86 if (! ft->seekable)
88 lsx_fail_errno(ft,SOX_EOF,"txw input file must be a file, not a pipe");
89 return(SOX_EOF);
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 */
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);
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
110 for( c = 0; c < 8; c++ )
111 lsx_readb(ft, &(gunk[c]));
113 * We should now be pointing at start of raw sample data in file
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"))
120 lsx_fail_errno(ft,SOX_EHDR,"Invalid filetype ID in input file header, != LM8953");
121 return(SOX_EOF);
124 * Set up the sample rate as indicated by the header
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;
145 break;
146 case 0x10:
147 if ( (gunk[5] & 0xFE) == 0x00 ) {
148 blewIt = 0;
149 ft->signal.rate = 1e5 / 2;
151 break;
152 case 0xF6:
153 if ( (gunk[5] & 0xFE) == 0x52 ) {
154 blewIt = 0;
155 ft->signal.rate = 1e5 / 6;
157 break;
159 if ( blewIt ) {
160 lsx_debug("Invalid sample rate identifier found %d", sample_rate);
161 ft->signal.rate = 1e5 / 3;
164 lsx_debug("Sample rate = %g", ft->signal.rate);
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;
170 return(SOX_SUCCESS);
174 * Read up to len samples from file.
175 * Convert to sox_sample_t.
176 * Place in buf[].
177 * Return number of samples read.
180 static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len)
182 priv_t * sk = (priv_t *) ft->priv;
183 size_t done = 0;
184 unsigned char uc1,uc2,uc3;
185 unsigned short s1,s2;
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.
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.
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 */
227 return done;
230 static int startwrite(sox_format_t * ft)
232 priv_t * sk = (priv_t *) ft->priv;
233 struct WaveHeader_ WH;
235 lsx_debug("tx16w selected output");
237 memset(&WH, 0, sizeof(struct WaveHeader_));
239 /* If you have to seek around the output file */
240 if (! ft->seekable)
242 lsx_fail_errno(ft,SOX_EOF,"Output .txw file must be a file, not a pipe");
243 return(SOX_EOF);
246 /* dummy numbers, just for place holder, real header is written
247 at end of processing, since byte count is needed */
249 lsx_writebuf(ft, &WH, (size_t) 32);
250 sk->bytes_out = 32;
251 return(SOX_SUCCESS);
254 static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len0)
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;
260 while (i < len) {
261 last_i = i;
262 if (sk->odd_flag) {
263 w1 = sk->odd;
264 sk->odd_flag = sox_false;
266 else w1 = *buf++ >> 20, ++i;
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;
276 sk->samples_out += 2;
277 sk->bytes_out += 3;
279 else {
280 sk->odd = w1;
281 sk->odd_flag = sox_true;
284 return i;
287 static int stopwrite(sox_format_t * ft)
289 priv_t * sk = (priv_t *) ft->priv;
290 struct WaveHeader_ WH;
291 int AttackLength, LoopLength, i;
293 if (sk->odd_flag) {
294 sox_sample_t pad = 0;
295 write_samples(ft, &pad, (size_t) 1);
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. */
302 lsx_debug("tx16w:output finished");
304 memset(&WH, 0, sizeof(struct WaveHeader_));
305 memcpy(WH.filetype, "LM8953", 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;
312 WH.format = 0xC9; /* loop off */
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;
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;
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;
332 else if (sk->samples_out >= 0x80) {
333 AttackLength = sk->samples_out -0x40;
334 LoopLength = 0x40;
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;
347 /* Fill up to 256 byte blocks; the TX16W seems to like that */
349 while ((sk->bytes_out % 0x100) != 0) {
350 lsx_writeb(ft, 0);
351 sk->bytes_out++;
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];
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];
364 lsx_rewind(ft);
365 lsx_writebuf(ft, &WH, (size_t) 32);
367 return(SOX_SUCCESS);
370 LSX_FORMAT_HANDLER(txw)
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)
381 return &handler;