This commit was generated by cvs2svn to compensate for changes in r5670,
[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 #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 }