comparison src/miscplay.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children a5df635868b2
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
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 /* #### Not aliasing-safe!! Must convert to use unions instead! */
566 size_t cnt = *sz / 2;
567 unsigned short *p;
568
569 *outbuf = *data;
570 p = (unsigned short *) *outbuf;
571 while (cnt--) {
572 *p++ = ((*p & 0x00ff) << 8) | (*p >> 8);
573 }
574 *data = p;
575 cnt = *sz;
576 *sz = 0;
577 return cnt;
578 }
579
580 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
581 signed mono data */
582 size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
583 {
584 REGISTER unsigned char *src;
585 REGISTER unsigned char *dest;
586 int rc,count;
587 signed short i;
588
589 count = *sz / 2;
590 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
591 else *sz = 0;
592 rc = count;
593 src = (unsigned char *) *data;
594 *outbuf =
595 dest = miscplay_sndbuf;
596 for (count /= 2; count--; ) {
597 i = ((int)(src[0]) +
598 256*(int)(src[1]) +
599 (int)(src[2]) +
600 256*(int)(src[3])) / 2;
601 src += 4;
602 *dest++ = (unsigned char)(i & 0xFF);
603 *dest++ = (unsigned char)((i / 256) & 0xFF); }
604 *data = src;
605 return(rc);
606 }
607
608 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
609 signed mono data */
610 size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
611 {
612 REGISTER unsigned char *src;
613 REGISTER unsigned char *dest;
614 int rc,count;
615 signed short i;
616
617 count = *sz / 2;
618 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
619 else *sz = 0;
620 rc = count;
621 src = (unsigned char *) *data;
622 *outbuf =
623 dest = miscplay_sndbuf;
624 for (count /= 2; count--; ) {
625 i = ((int)(src[1]) +
626 256*(int)(src[0]) +
627 (int)(src[3]) +
628 256*(int)(src[2])) / 2;
629 src += 4;
630 *dest++ = (unsigned char)((i / 256) & 0xFF);
631 *dest++ = (unsigned char)(i & 0xFF); }
632 *data = src;
633 return(rc);
634 }
635
636 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
637 size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
638 {
639 REGISTER unsigned char *src;
640 REGISTER unsigned char *dest;
641 int rc,count;
642
643 count = *sz / 2;
644 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
645 else *sz = 0;
646 rc = count;
647 src = (unsigned char *) *data;
648 *outbuf =
649 dest = miscplay_sndbuf;
650 while (count--) {
651 *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
652 src += 2;
653 }
654 *data = src;
655 return(rc);
656 }
657
658 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
659 size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
660 {
661 REGISTER unsigned char *src;
662 REGISTER unsigned char *dest;
663 int rc,count;
664
665 count = *sz / 2;
666 if (count > SNDBUFSZ) { *sz -= 2*SNDBUFSZ; count = SNDBUFSZ; }
667 else *sz = 0;
668 rc = count;
669 src = (unsigned char *) *data;
670 *outbuf =
671 dest = miscplay_sndbuf;
672 while (count--) {
673 *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
674 src += 2;
675 }
676 *data = src;
677 return(rc);
678 }
679
680 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
681 mono data */
682 size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
683 {
684 REGISTER unsigned char *src;
685 REGISTER unsigned char *dest;
686 int rc,count;
687
688 count = *sz / 4;
689 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
690 else *sz = 0;
691 rc = count;
692 src = (unsigned char *) *data;
693 *outbuf =
694 dest = miscplay_sndbuf;
695 while (count--) {
696 *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
697 (int)((signed char *)src)[3]) / 2 ^ 0x80);
698 src += 4;
699 }
700 *data = src;
701 return(rc);
702 }
703
704 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
705 mono data */
706 size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
707 {
708 REGISTER unsigned char *src;
709 REGISTER unsigned char *dest;
710 int rc,count;
711
712 count = *sz / 4;
713 if (count > SNDBUFSZ) { *sz -= 4*SNDBUFSZ; count = SNDBUFSZ; }
714 else *sz = 0;
715 rc = count;
716 src = (unsigned char *) *data;
717 *outbuf =
718 dest = miscplay_sndbuf;
719 while (count--) {
720 *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
721 (int)((signed char *)src)[2]) / 2 ^ 0x80);
722 src += 4;
723 }
724 *data = src;
725 return(rc);
726 }
727
728 /* Look at the header of the sound file and try to determine the format;
729 we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
730 else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
731 fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
732 int *tracks,
733 size_t (**parsesndfile)(void **,size_t *sz,
734 void **))
735 {
736 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
737 if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
738 (format[22]+256*format[23]) ==
739 ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
740 *fmt = AFMT_U8;
741 *speed = 8000;
742 *tracks = 2;
743 *parsesndfile = parsevoc;
744 return(fmtVoc); }
745 else if (!memcmp(format,"RIFF",4) &&
746 !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
747 if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
748 memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
749 return(fmtIllegal);
750 *fmt = (format[32]/(*tracks = format[22])) == 1 ?
751 AFMT_U8 : AFMT_S16_LE;
752 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
753 *speed = format[24]+256*(format[25]+256*
754 (format[26]+256*format[27]));
755 *parsesndfile = parsewave;
756 return(fmtWave); }
757 else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
758 if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
759 *fmt = AFMT_MU_LAW;
760 *speed = 8000;
761 *tracks = 1;
762 *parsesndfile = parsesundecaudio;
763 return(fmtSunAudio); }
764 if (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
765 else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
766 else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
767 else return(fmtIllegal);
768 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
769 *speed = format[19]+256*(format[18]+256*
770 (format[17]+256*format[16]));
771 *tracks = format[23];
772 *parsesndfile = parsesundecaudio;
773 return(fmtSunAudio); }
774 else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
775 if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
776 *fmt = AFMT_MU_LAW;
777 *speed = 8000;
778 *tracks = 1;
779 *parsesndfile = parsesundecaudio;
780 return(fmtSunAudio); }
781 if (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
782 else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
783 else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
784 else return(fmtIllegal);
785 /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex */
786 *speed = format[16]+256*(format[17]+256*
787 (format[18]+256*format[19]));
788 *tracks = format[20];
789 *parsesndfile = parsesundecaudio;
790 return(fmtSunAudio); }
791 else {
792 *fmt = AFMT_U8;
793 *speed = 8000;
794 *tracks = 1;
795 *parsesndfile = parseraw;
796 return(fmtRaw); }
797 }