comparison src/miscplay.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents
children 2f8bb876ab1d
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
1 /* miscplay.c - general routines related to playing sounds
2 **
3 ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4 ** This was sawed out from version 1.3 of linuxplay.c by
5 ** Robert Bihlmeyer <robbe@orcus.priv.at>.
6 **
7 ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
8 ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
9 ** information.
10 **
11 ** Permission to use, copy, modify, and distribute this software and its
12 ** documentation for any purpose and without fee is hereby granted, provided
13 ** that the above copyright notice appear in all copies and that both that
14 ** copyright notice and this permission notice appear in supporting
15 ** documentation. This software is provided "as is" without express or
16 ** implied warranty.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "miscplay.h"
24 #include "lisp.h"
25 #include "syssignal.h"
26 #include "sysfile.h"
27 #define warn(str) message("audio: %s ",GETTEXT(str))
28
29 #include <stdlib.h>
30
31 #ifdef __GNUC__
32 #define UNUSED(x) ((void)(x))
33 #else
34 #define UNUSED(x)
35 #define __inline__
36 #endif
37
38 /* Maintain global variable for keeping parser state information; this struct
39 is set to zero before the first invocation of the parser. The use of a
40 global variable prevents multiple concurrent executions of this code, but
41 this does not happen anyways... */
42 enum wvState
43 { wvMain,
44 wvSubchunk,
45 wvOutOfBlock,
46 wvSkipChunk,
47 wvSoundChunk,
48 wvFatal,
49 wvFatalNotify
50 };
51
52 static union {
53 struct {
54 int align;
55 enum wvState state;
56 size_t left;
57 unsigned char leftover[HEADERSZ];
58 signed long chunklength;
59 } wave;
60 struct {
61 int align;
62 int isdata;
63 int skipping;
64 size_t left;
65 unsigned char leftover[HEADERSZ];
66 } audio;
67 } parsestate;
68
69 /* Use a global buffer as scratch-pad for possible conversions of the
70 sampling format */
71 unsigned char miscplay_sndbuf[SNDBUFSZ];
72
73 /* Initialize global parser state information to zero */
74 void reset_parsestate()
75 {
76 memset(&parsestate,0,sizeof(parsestate));
77 }
78
79 /* Verify that we could fully parse the entire soundfile; this is needed
80 only for files in WAVE format */
81 int parse_wave_complete()
82 {
83 if (parsestate.wave.state != wvOutOfBlock &&
84 parsestate.wave.state != wvFatal) {
85 warn("Unexpected end of WAVE file");
86 return 0;
87 } else
88 return 1;
89 }
90
91 /* There is no special treatment required for parsing raw data files; we
92 assume that these files contain data in 8bit unsigned format that
93 has been sampled at 8kHz; there is no extra header */
94 static size_t parseraw(void **data,size_t *sz,void **outbuf)
95 {
96 int rc = *sz;
97
98 *outbuf = *data;
99 *sz = 0;
100 return(rc);
101 }
102
103 /* Currently we cannot cope with files in VOC format; if you really need
104 to play these files, they should be converted by using SOX */
105 static size_t parsevoc(void **data,size_t *sz,void **outbuf)
106 {
107 UNUSED(data);
108 UNUSED(sz);
109 UNUSED(outbuf);
110 return(0);
111 }
112
113 /* We need to perform some look-ahead in order to parse files in WAVE format;
114 this might require re-partioning of the data segments if headers cross the
115 boundaries between two read operations. This is done in a two-step way:
116 first we request a certain amount of bytes... */
117 static __inline__ int waverequire(void **data,size_t *sz,size_t rq)
118 {
119 int rc = 1;
120
121 if (rq > HEADERSZ) {
122 warn("Header size exceeded while parsing WAVE file");
123 parsestate.wave.state = wvFatal;
124 *sz = 0;
125 return(0); }
126 if ((rq -= parsestate.wave.left) <= 0)
127 return(rc);
128 if (rq > *sz) {rq = *sz; rc = 0;}
129 memcpy(parsestate.wave.leftover+parsestate.wave.left,
130 *data,rq);
131 parsestate.wave.left += rq;
132 (*(unsigned char **)data) += rq;
133 *sz -= rq;
134 return(rc);
135 }
136
137 /* ...and next we remove this many bytes from the buffer */
138 static __inline__ void waveremove(size_t rq)
139 {
140 if (parsestate.wave.left <= rq)
141 parsestate.wave.left = 0;
142 else {
143 parsestate.wave.left -= rq;
144 memmove(parsestate.wave.leftover,
145 parsestate.wave.leftover+rq,
146 parsestate.wave.left); }
147 return;
148 }
149
150 /* Sound files in WAVE format can contain an arbitrary amount of tagged
151 chunks; this requires quite some effort for parsing the data */
152 static size_t parsewave(void **data,size_t *sz,void **outbuf)
153 {
154 for (;;)
155 switch (parsestate.wave.state) {
156 case wvMain:
157 if (!waverequire(data,sz,20))
158 return(0);
159 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
160 parsestate.wave.chunklength = parsestate.wave.leftover[16] +
161 256*(parsestate.wave.leftover[17] +
162 256*(parsestate.wave.leftover[18] +
163 256*parsestate.wave.leftover[19]));
164 waveremove(20);
165 parsestate.wave.state = wvSubchunk;
166 break;
167 case wvSubchunk:
168 if (!waverequire(data,sz,parsestate.wave.chunklength))
169 return(0);
170 parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1
171 : parsestate.wave.leftover[12];
172 if (parsestate.wave.align != 1 &&
173 parsestate.wave.align != 2 &&
174 parsestate.wave.align != 4) {
175 warn("Illegal datawidth detected while parsing WAVE file");
176 parsestate.wave.state = wvFatal; }
177 else
178 parsestate.wave.state = wvOutOfBlock;
179 waveremove(parsestate.wave.chunklength);
180 break;
181 case wvOutOfBlock:
182 if (!waverequire(data,sz,8))
183 return(0);
184 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
185 parsestate.wave.chunklength = parsestate.wave.leftover[4] +
186 256*(parsestate.wave.leftover[5] +
187 256*(parsestate.wave.leftover[6] +
188 256*(parsestate.wave.leftover[7] & 0x7F)));
189 if (memcmp(parsestate.wave.leftover,"data",4))
190 parsestate.wave.state = wvSkipChunk;
191 else
192 parsestate.wave.state = wvSoundChunk;
193 waveremove(8);
194 break;
195 case wvSkipChunk:
196 if (parsestate.wave.chunklength > 0 && *sz > 0 &&
197 (signed long)*sz < (signed long)parsestate.wave.chunklength) {
198 parsestate.wave.chunklength -= *sz;
199 *sz = 0; }
200 else {
201 if (parsestate.wave.chunklength > 0 && *sz > 0) {
202 *sz -= parsestate.wave.chunklength;
203 (*(unsigned char **)data) += parsestate.wave.chunklength; }
204 parsestate.wave.state = wvOutOfBlock; }
205 break;
206 case wvSoundChunk: {
207 size_t count,rq;
208 if (parsestate.wave.left) { /* handle leftover bytes from last
209 alignment operation */
210 count = parsestate.wave.left;
211 rq = HEADERSZ-count;
212 if (rq > (size_t) parsestate.wave.chunklength)
213 rq = parsestate.wave.chunklength;
214 if (!waverequire(data,sz,rq)) {
215 parsestate.wave.chunklength -= parsestate.wave.left - count;
216 return(0); }
217 parsestate.wave.chunklength -= rq;
218 *outbuf = parsestate.wave.leftover;
219 parsestate.wave.left = 0;
220 return(rq); }
221 if (*sz >= (size_t) parsestate.wave.chunklength) {
222 count = parsestate.wave.chunklength;
223 rq = 0; }
224 else {
225 count = *sz;
226 count -= rq = count % parsestate.wave.align; }
227 *outbuf = *data;
228 (*(unsigned char **)data) += count;
229 *sz -= count;
230 if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) {
231 parsestate.wave.state = wvOutOfBlock;
232 /* Some broken software (e.g. SOX) attaches junk to the end of a sound
233 chunk; so, let's ignore this... */
234 if (parsestate.wave.chunklength)
235 parsestate.wave.state = wvSkipChunk; }
236 else if (rq)
237 /* align data length to a multiple of datasize; keep additional data
238 in "leftover" buffer --- this is necessary to ensure proper
239 functioning of the sndcnv... routines */
240 waverequire(data,sz,rq);
241 return(count); }
242 case wvFatalNotify:
243 warn("Irrecoverable error while parsing WAVE file");
244 parsestate.wave.state = wvFatal;
245 break;
246 case wvFatal:
247 default:
248 *sz = 0;
249 return(0); }
250 }
251
252 /* Strip the header from files in Sun/DEC audio format; this requires some
253 extra processing as the header can be an arbitrary size and it might
254 result in alignment errors for subsequent conversions --- thus we do
255 some buffering, where needed */
256 static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf)
257 {
258 /* There is data left over from the last invocation of this function; join
259 it with the new data and return a sound chunk that is as big as a
260 single entry */
261 if (parsestate.audio.left) {
262 if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) {
263 int count;
264 memmove(parsestate.audio.leftover + parsestate.audio.left,
265 *data,
266 count = parsestate.audio.align - parsestate.audio.left);
267 *outbuf = parsestate.audio.leftover;
268 *sz -= count;
269 *data = (*(char **)data) + count;
270 parsestate.audio.left = 0;
271 return(parsestate.audio.align); }
272 else {
273 /* We need even more data in order to get one complete single entry! */
274 memmove(parsestate.audio.leftover + parsestate.audio.left,
275 *data,
276 *sz);
277 *data = (*(char **)data) + *sz;
278 parsestate.audio.left += *sz;
279 *sz = 0;
280 return(0); } }
281
282 /* This is the main sound chunk, strip of any extra data that does not fit
283 the alignment requirements and move these bytes into the leftover buffer*/
284 if (parsestate.audio.isdata) {
285 int rc = *sz;
286 *outbuf = *data;
287 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
288 memmove(parsestate.audio.leftover,
289 (char *)*outbuf + rc - parsestate.audio.left,
290 parsestate.audio.left);
291 rc -= parsestate.audio.left; }
292 *sz = 0;
293 return(rc); }
294
295 /* This is the first invocation of this function; we need to parse the
296 header information and determine how many bytes we need to skip until
297 the start of the sound chunk */
298 if (!parsestate.audio.skipping) {
299 unsigned char *header = (unsigned char *) *data;
300 if (*sz < 8) {
301 warn("Irrecoverable error while parsing Sun/DEC audio file");
302 return(0); }
303 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
304 if (header[3]) { /* Sun audio (big endian) */
305 parsestate.audio.align = ((header[15] > 2)+1)*header[23];
306 parsestate.audio.skipping = header[7]+256*(header[6]+256*
307 (header[5]+256*header[4])); }
308 else { /* DEC audio (little endian) */
309 parsestate.audio.align = ((header[12] > 2)+1)*header[20];
310 parsestate.audio.skipping = header[4]+256*(header[5]+256*
311 (header[6]+256*header[7])); }}
312
313 /* We are skipping extra data that has been attached to header; most usually
314 this will be just a comment, such as the original filename and/or the
315 creation date. Make sure that we do not return less than one single sound
316 sample entry to the caller; if this happens, rather decide to move those
317 few bytes into the leftover buffer and deal with it later */
318 if (*sz >= (size_t) parsestate.audio.skipping) {
319 /* Skip just the header information and return the sound chunk */
320 int rc = *sz - parsestate.audio.skipping;
321 *outbuf = (char *)*data + parsestate.audio.skipping;
322 if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
323 memmove(parsestate.audio.leftover,
324 (char *)*outbuf + rc - parsestate.audio.left,
325 parsestate.audio.left);
326 rc -= parsestate.audio.left; }
327 *sz = 0;
328 parsestate.audio.skipping = 0;
329 parsestate.audio.isdata++;
330 return(rc); }
331 else {
332 /* Skip everything */
333 parsestate.audio.skipping -= *sz;
334 return(0); }
335 }
336
337 /* If the soundcard could not be set to natively support the data format, we
338 try to do some limited on-the-fly conversion to a different format; if
339 no conversion is needed, though, we can output directly */
340 size_t sndcnvnop(void **data,size_t *sz,void **outbuf)
341 {
342 int rc = *sz;
343
344 *outbuf = *data;
345 *sz = 0;
346 return(rc);
347 }
348
349 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
350 size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf)
351 {
352 REGISTER unsigned char *src;
353 REGISTER unsigned char *dest;
354 int rc,count;
355
356 count = *sz / 2;
357 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
358 else *sz = 0;
359 rc = count;
360 src = (unsigned char *) *data;
361 *outbuf =
362 dest = miscplay_sndbuf;
363 while (count--)
364 *dest++ = (unsigned char)(((int)*(src)++ +
365 (int)*(src)++) / 2);
366 *data = src;
367 return(rc);
368 }
369
370 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
371 size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
372 {
373 REGISTER unsigned char *src;
374 REGISTER unsigned char *dest;
375 int rc, count;
376
377 count = *sz / 2;
378 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
379 else *sz = 0;
380 rc = count;
381 src = (unsigned char *) *data;
382 *outbuf =
383 dest = miscplay_sndbuf;
384 while (count--)
385 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
386 (int)*((signed char *)(src++))) / 2);
387 *data = src;
388 return(rc);
389 }
390
391 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
392 size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
393 {
394 REGISTER unsigned char *src;
395 REGISTER unsigned char *dest;
396 int rc,count;
397
398 count = *sz / 2;
399 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
400 else *sz = 0;
401 rc = count;
402 src = (unsigned char *) *data;
403 *outbuf =
404 dest = miscplay_sndbuf;
405 while (count--)
406 *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
407 (int)*((signed char *)(src++))) / 2) ^ 0x80;
408 *data = src;
409 return(rc);
410 }
411
412 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
413 size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
414 {
415 REGISTER unsigned char *src;
416 REGISTER unsigned char *dest;
417 int rc,count;
418
419 count = *sz;
420 if (count > SNDBUFSZ) { *sz -= SNDBUFSZ; count = SNDBUFSZ; }
421 else *sz = 0;
422 rc = count;
423 src = (unsigned char *) *data;
424 *outbuf =
425 dest = miscplay_sndbuf;
426 while (count--)
427 *dest++ = *(src)++ ^ 0x80;
428 *data = src;
429 return(rc);
430 }
431
432 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
433 number --- I hope, I got this conversion right :-) */
434 static __inline__ signed char int2ulaw(int i)
435 {
436 /* Lookup table for fast calculation of number of bits that need shifting*/
437 static short int t_bits[128] = {
438 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
439 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
440 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
441 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
442 REGISTER int bits,logi;
443
444 /* unrolling this condition (hopefully) improves execution speed */
445 if (i < 0) {
446 if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
447 logi = (i >> ((bits = t_bits[i/256])+4));
448 return((bits << 4 | logi) ^ 0x7F); }
449 else {
450 if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
451 logi = (i >> ((bits = t_bits[i/256])+4));
452 return(~(bits << 4 | logi)); }
453 }
454
455 /* Convert from 8 bit ulaw mono to 8 bit linear mono */
456 size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf)
457 {
458 /* conversion table stolen from Linux's ulaw.h */
459 static unsigned char ulaw_dsp[] = {
460 3, 7, 11, 15, 19, 23, 27, 31,
461 35, 39, 43, 47, 51, 55, 59, 63,
462 66, 68, 70, 72, 74, 76, 78, 80,
463 82, 84, 86, 88, 90, 92, 94, 96,
464 98, 99, 100, 101, 102, 103, 104, 105,
465 106, 107, 108, 109, 110, 111, 112, 113,
466 113, 114, 114, 115, 115, 116, 116, 117,
467 117, 118, 118, 119, 119, 120, 120, 121,
468 121, 121, 122, 122, 122, 122, 123, 123,
469 123, 123, 124, 124, 124, 124, 125, 125,
470 125, 125, 125, 125, 126, 126, 126, 126,
471 126, 126, 126, 126, 127, 127, 127, 127,
472 127, 127, 127, 127, 127, 127, 127, 127,
473 128, 128, 128, 128, 128, 128, 128, 128,
474 128, 128, 128, 128, 128, 128, 128, 128,
475 128, 128, 128, 128, 128, 128, 128, 128,
476 253, 249, 245, 241, 237, 233, 229, 225,
477 221, 217, 213, 209, 205, 201, 197, 193,
478 190, 188, 186, 184, 182, 180, 178, 176,
479 174, 172, 170, 168, 166, 164, 162, 160,
480 158, 157, 156, 155, 154, 153, 152, 151,
481 150, 149, 148, 147, 146, 145, 144, 143,
482 143, 142, 142, 141, 141, 140, 140, 139,
483 139, 138, 138, 137, 137, 136, 136, 135,
484 135, 135, 134, 134, 134, 134, 133, 133,
485 133, 133, 132, 132, 132, 132, 131, 131,
486 131, 131, 131, 131, 130, 130, 130, 130,
487 130, 130, 130, 130, 129, 129, 129, 129,
488 129, 129, 129, 129, 129, 129, 129, 129,
489 128, 128, 128, 128, 128, 128, 128, 128,
490 128, 128, 128, 128, 128, 128, 128, 128,
491 128, 128, 128, 128, 128, 128, 128, 128,
492 };
493 unsigned char *p=(unsigned char *)*data;
494
495 *outbuf = *data;
496 while ((*sz)--)
497 *p++ = ulaw_dsp[*p];
498 *sz = 0;
499 *data = p;
500 return p - (unsigned char *)*outbuf;
501 }
502
503 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
504 size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
505 {
506
507 static short int ulaw2int[256] = {
508 /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
509 -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
510 -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
511 -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
512 -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
513 -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
514 -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
515 -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
516 -1438, -1374, -1310, -1246, -1182, -1118, -1054, -990,
517 -942, -910, -878, -846, -814, -782, -750, -718,
518 -686, -654, -622, -590, -558, -526, -494, -462,
519 -438, -422, -406, -390, -374, -358, -342, -326,
520 -310, -294, -278, -262, -246, -230, -214, -198,
521 -186, -178, -170, -162, -154, -146, -138, -130,
522 -122, -114, -106, -98, -90, -82, -74, -66,
523 -60, -56, -52, -48, -44, -40, -36, -32,
524 -28, -24, -20, -16, -12, -8, -4, +0,
525 +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
526 +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
527 +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
528 +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
529 +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
530 +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
531 +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
532 +1438, +1374, +1310, +1246, +1182, +1118, +1054, +990,
533 +942, +910, +878, +846, +814, +782, +750, +718,
534 +686, +654, +622, +590, +558, +526, +494, +462,
535 +438, +422, +406, +390, +374, +358, +342, +326,
536 +310, +294, +278, +262, +246, +230, +214, +198,
537 +186, +178, +170, +162, +154, +146, +138, +130,
538 +122, +114, +106, +98, +90, +82, +74, +66,
539 +60, +56, +52, +48, +44, +40, +36, +32,
540 +28, +24, +20, +16, +12, +8, +4, +0};
541
542 REGISTER unsigned char *src;
543 REGISTER unsigned char *dest;
544 int rc,count;
545
546 count = *sz / 2;
547 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
548 else *sz = 0;
549 rc = count;
550 src = (unsigned char *) *data;
551 *outbuf =
552 dest = miscplay_sndbuf;
553 while (count--)
554 /* it is not possible to directly interpolate between two ulaw encoded
555 data bytes, thus we need to convert to linear format first and later
556 we convert back to ulaw format */
557 *dest++ = int2ulaw(ulaw2int[*(src)++] +
558 ulaw2int[*(src)++]);
559 *data = src;
560 return(rc);
561 }
562
563 size_t sndcnv16swap(void **data,size_t *sz,void **outbuf)
564 {
565 size_t cnt = *sz / 2;
566 unsigned short *p;
567
568 *outbuf = *data;
569 p = (unsigned short *) *outbuf;
570 while (cnt--) {
571 *p++ = ((*p & 0x00ff) << 8) | (*p >> 8);
572 }
573 *data = p;
574 cnt = *sz;
575 *sz = 0;
576 return cnt;
577 }
578
579 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
580 signed mono data */
581 size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
582 {
583 REGISTER unsigned char *src;
584 REGISTER unsigned char *dest;
585 int rc,count;
586 signed short i;
587
588 count = *sz / 2;
589 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
590 else *sz = 0;
591 rc = count;
592 src = (unsigned char *) *data;
593 *outbuf =
594 dest = miscplay_sndbuf;
595 for (count /= 2; count--; ) {
596 i = ((int)(src[0]) +
597 256*(int)(src[1]) +
598 (int)(src[2]) +
599 256*(int)(src[3])) / 2;
600 src += 4;
601 *dest++ = (unsigned char)(i & 0xFF);
602 *dest++ = (unsigned char)((i / 256) & 0xFF); }
603 *data = src;
604 return(rc);
605 }
606
607 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
608 signed mono data */
609 size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
610 {
611 REGISTER unsigned char *src;
612 REGISTER unsigned char *dest;
613 int rc,count;
614 signed short i;
615
616 count = *sz / 2;
617 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
618 else *sz = 0;
619 rc = count;
620 src = (unsigned char *) *data;
621 *outbuf =
622 dest = miscplay_sndbuf;
623 for (count /= 2; count--; ) {
624 i = ((int)(src[1]) +
625 256*(int)(src[0]) +
626 (int)(src[3]) +
627 256*(int)(src[2])) / 2;
628 src += 4;
629 *dest++ = (unsigned char)((i / 256) & 0xFF);
630 *dest++ = (unsigned char)(i & 0xFF); }
631 *data = src;
632 return(rc);
633 }
634
635 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
636 size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
637 {
638 REGISTER unsigned char *src;
639 REGISTER unsigned char *dest;
640 int rc,count;
641
642 count = *sz / 2;
643 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
644 else *sz = 0;
645 rc = count;
646 src = (unsigned char *) *data;
647 *outbuf =
648 dest = miscplay_sndbuf;
649 while (count--) {
650 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
651 src += 2;
652 }
653 *data = src;
654 return(rc);
655 }
656
657 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
658 size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
659 {
660 REGISTER unsigned char *src;
661 REGISTER unsigned char *dest;
662 int rc,count;
663
664 count = *sz / 2;
665 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
666 else *sz = 0;
667 rc = count;
668 src = (unsigned char *) *data;
669 *outbuf =
670 dest = miscplay_sndbuf;
671 while (count--) {
672 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
673 src += 2;
674 }
675 *data = src;
676 return(rc);
677 }
678
679 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
680 mono data */
681 size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
682 {
683 REGISTER unsigned char *src;
684 REGISTER unsigned char *dest;
685 int rc,count;
686
687 count = *sz / 4;
688 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
689 else *sz = 0;
690 rc = count;
691 src = (unsigned char *) *data;
692 *outbuf =
693 dest = miscplay_sndbuf;
694 while (count--) {
695 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
696 (int)((signed char *)src)[3]) / 2 ^ 0x80);
697 src += 4;
698 }
699 *data = src;
700 return(rc);
701 }
702
703 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
704 mono data */
705 size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
706 {
707 REGISTER unsigned char *src;
708 REGISTER unsigned char *dest;
709 int rc,count;
710
711 count = *sz / 4;
712 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
713 else *sz = 0;
714 rc = count;
715 src = (unsigned char *) *data;
716 *outbuf =
717 dest = miscplay_sndbuf;
718 while (count--) {
719 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
720 (int)((signed char *)src)[2]) / 2 ^ 0x80);
721 src += 4;
722 }
723 *data = src;
724 return(rc);
725 }
726
727 /* Look at the header of the sound file and try to determine the format;
728 we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
729 else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
730 fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
731 int *tracks,
732 size_t (**parsesndfile)(void **,size_t *sz,
733 void **))
734 {
735 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
736 if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
737 (format[22]+256*format[23]) ==
738 ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
739 *fmt = AFMT_U8;
740 *speed = 8000;
741 *tracks = 2;
742 *parsesndfile = parsevoc;
743 return(fmtVoc); }
744 else if (!memcmp(format,"RIFF",4) &&
745 !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
746 if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
747 memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
748 return(fmtIllegal);
749 *fmt = (format[32]/(*tracks = format[22])) == 1 ?
750 AFMT_U8 : AFMT_S16_LE;
751 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
752 *speed = format[24]+256*(format[25]+256*
753 (format[26]+256*format[27]));
754 *parsesndfile = parsewave;
755 return(fmtWave); }
756 else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
757 if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
758 *fmt = AFMT_MU_LAW;
759 *speed = 8000;
760 *tracks = 1;
761 *parsesndfile = parsesundecaudio;
762 return(fmtSunAudio); }
763 if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
764 else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
765 else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
766 else return(fmtIllegal);
767 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
768 *speed = format[19]+256*(format[18]+256*
769 (format[17]+256*format[16]));
770 *tracks = format[23];
771 *parsesndfile = parsesundecaudio;
772 return(fmtSunAudio); }
773 else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
774 if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
775 *fmt = AFMT_MU_LAW;
776 *speed = 8000;
777 *tracks = 1;
778 *parsesndfile = parsesundecaudio;
779 return(fmtSunAudio); }
780 if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
781 else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
782 else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
783 else return(fmtIllegal);
784 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
785 *speed = format[16]+256*(format[17]+256*
786 (format[18]+256*format[19]));
787 *tracks = format[20];
788 *parsesndfile = parsesundecaudio;
789 return(fmtSunAudio); }
790 else {
791 *fmt = AFMT_U8;
792 *speed = 8000;
793 *tracks = 1;
794 *parsesndfile = parseraw;
795 return(fmtRaw); }
796 }