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