(U-0002195D): Add `ideographic-structure'; add `sound@ja/on'; add
[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     {
364       *dest++ = (unsigned char)(((int)*(src) +
365                                  (int)*(src+1)) / 2);
366       src += 2;
367     }
368   *data   = src;
369   return(rc);
370 }
371
372 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
373 size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
374 {
375   REGISTER unsigned char *src;
376   REGISTER unsigned char *dest;
377   int rc, count;
378
379   count = *sz / 2;
380   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
381   else                    *sz   = 0;
382   rc      = count;
383   src     = (unsigned char *) *data;
384   *outbuf =
385   dest    = miscplay_sndbuf;
386   while (count--)
387     {
388       *dest++ = (unsigned char)(((int)*((signed char *)(src)) +
389                                  (int)*((signed char *)(src+1))) / 2);
390       src  += 2;
391     }
392   *data   = src;
393   return(rc);
394 }
395
396 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
397 size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
398 {
399   REGISTER unsigned char *src;
400   REGISTER unsigned char *dest;
401   int rc,count;
402
403   count = *sz / 2;
404   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
405   else                    *sz   = 0;
406   rc      = count;
407   src     = (unsigned char *) *data;
408   *outbuf =
409   dest    = miscplay_sndbuf;
410   while (count--)
411     {
412       *dest++ = (unsigned char)(((int)*((signed char *)(src)) +
413                                  (int)*((signed char *)(src+1))) / 2) ^ 0x80;
414       src += 2;
415     }
416   *data   = src;
417   return(rc);
418 }
419
420 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
421 size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
422 {
423   REGISTER unsigned char *src;
424   REGISTER unsigned char *dest;
425   int rc,count;
426
427   count = *sz;
428   if (count > SNDBUFSZ) { *sz  -= SNDBUFSZ; count = SNDBUFSZ; }
429   else                    *sz   = 0;
430   rc      = count;
431   src     = (unsigned char *) *data;
432   *outbuf =
433   dest    = miscplay_sndbuf;
434   while (count--)
435     *dest++ = *(src)++ ^ 0x80;
436   *data   = src;
437   return(rc);
438 }
439
440 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
441    number --- I hope, I got this conversion right :-) */
442 static inline signed char int2ulaw(int i)
443 {
444     /* Lookup table for fast calculation of number of bits that need shifting*/
445     static short int t_bits[128] = {
446       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,
447       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,
448       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,
449       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};
450     REGISTER int bits,logi;
451
452     /* unrolling this condition (hopefully) improves execution speed */
453     if (i < 0) {
454       if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
455       logi = (i >> ((bits = t_bits[i/256])+4));
456       return((bits << 4 | logi) ^ 0x7F); }
457     else {
458       if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
459       logi = (i >> ((bits = t_bits[i/256])+4));
460       return(~(bits << 4 | logi)); }
461 }
462
463 /* Convert from 8 bit ulaw mono to 8 bit linear mono */
464 size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf)
465 {
466   /* conversion table stolen from Linux's ulaw.h */
467   static unsigned char ulaw_dsp[] = {
468      3,    7,   11,   15,   19,   23,   27,   31,
469     35,   39,   43,   47,   51,   55,   59,   63,
470     66,   68,   70,   72,   74,   76,   78,   80,
471     82,   84,   86,   88,   90,   92,   94,   96,
472     98,   99,  100,  101,  102,  103,  104,  105,
473    106,  107,  108,  109,  110,  111,  112,  113,
474    113,  114,  114,  115,  115,  116,  116,  117,
475    117,  118,  118,  119,  119,  120,  120,  121,
476    121,  121,  122,  122,  122,  122,  123,  123,
477    123,  123,  124,  124,  124,  124,  125,  125,
478    125,  125,  125,  125,  126,  126,  126,  126,
479    126,  126,  126,  126,  127,  127,  127,  127,
480    127,  127,  127,  127,  127,  127,  127,  127,
481    128,  128,  128,  128,  128,  128,  128,  128,
482    128,  128,  128,  128,  128,  128,  128,  128,
483    128,  128,  128,  128,  128,  128,  128,  128,
484    253,  249,  245,  241,  237,  233,  229,  225,
485    221,  217,  213,  209,  205,  201,  197,  193,
486    190,  188,  186,  184,  182,  180,  178,  176,
487    174,  172,  170,  168,  166,  164,  162,  160,
488    158,  157,  156,  155,  154,  153,  152,  151,
489    150,  149,  148,  147,  146,  145,  144,  143,
490    143,  142,  142,  141,  141,  140,  140,  139,
491    139,  138,  138,  137,  137,  136,  136,  135,
492    135,  135,  134,  134,  134,  134,  133,  133,
493    133,  133,  132,  132,  132,  132,  131,  131,
494    131,  131,  131,  131,  130,  130,  130,  130,
495    130,  130,  130,  130,  129,  129,  129,  129,
496    129,  129,  129,  129,  129,  129,  129,  129,
497    128,  128,  128,  128,  128,  128,  128,  128,
498    128,  128,  128,  128,  128,  128,  128,  128,
499    128,  128,  128,  128,  128,  128,  128,  128,
500   };
501   unsigned char *p=(unsigned char *)*data;
502
503   *outbuf = *data;
504   while ((*sz)--)
505     {
506       *p = ulaw_dsp[*p];
507       p++;
508     }
509   *sz = 0;
510   *data = p;
511   return p - (unsigned char *)*outbuf;
512 }
513
514 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
515 size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
516 {
517
518   static short int ulaw2int[256] = {
519     /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
520     -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
521     -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
522      -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
523      -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
524      -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
525      -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
526      -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
527      -1438, -1374, -1310, -1246, -1182, -1118, -1054,  -990,
528       -942,  -910,  -878,  -846,  -814,  -782,  -750,  -718,
529       -686,  -654,  -622,  -590,  -558,  -526,  -494,  -462,
530       -438,  -422,  -406,  -390,  -374,  -358,  -342,  -326,
531       -310,  -294,  -278,  -262,  -246,  -230,  -214,  -198,
532       -186,  -178,  -170,  -162,  -154,  -146,  -138,  -130,
533       -122,  -114,  -106,   -98,   -90,   -82,   -74,   -66,
534        -60,   -56,   -52,   -48,   -44,   -40,   -36,   -32,
535        -28,   -24,   -20,   -16,   -12,    -8,    -4,    +0,
536     +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
537     +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
538      +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
539      +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
540      +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
541      +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
542      +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
543      +1438, +1374, +1310, +1246, +1182, +1118, +1054,  +990,
544       +942,  +910,  +878,  +846,  +814,  +782,  +750,  +718,
545       +686,  +654,  +622,  +590,  +558,  +526,  +494,  +462,
546       +438,  +422,  +406,  +390,  +374,  +358,  +342,  +326,
547       +310,  +294,  +278,  +262,  +246,  +230,  +214,  +198,
548       +186,  +178,  +170,  +162,  +154,  +146,  +138,  +130,
549       +122,  +114,  +106,   +98,   +90,   +82,   +74,   +66,
550        +60,   +56,   +52,   +48,   +44,   +40,   +36,   +32,
551        +28,   +24,   +20,   +16,   +12,    +8,    +4,    +0};
552
553   REGISTER unsigned char *src;
554   REGISTER unsigned char *dest;
555   int rc,count;
556
557   count = *sz / 2;
558   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
559   else                    *sz   = 0;
560   rc      = count;
561   src     = (unsigned char *) *data;
562   *outbuf =
563   dest    = miscplay_sndbuf;
564   while (count--)
565     {
566       /* it is not possible to directly interpolate between two ulaw encoded
567          data bytes, thus we need to convert to linear format first and later
568          we convert back to ulaw format */
569       *dest++ = int2ulaw(ulaw2int[*src] +
570                          ulaw2int[*(src+1)]);
571       src  += 2;
572     }
573   *data = src;
574   return(rc);
575 }
576
577 size_t sndcnv16swap(void **data,size_t *sz,void **outbuf)
578 {
579   size_t cnt = *sz / 2;
580   unsigned short *p;
581
582   *outbuf = *data;
583   p = (unsigned short *) *outbuf;
584   while (cnt--)
585     {
586       *p = ((*p & 0x00ff) << 8) | (*p >> 8);
587       p++;
588     }
589   *data = p;
590   cnt = *sz;
591   *sz = 0;
592   return cnt;
593 }
594
595 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
596    signed mono data */
597 size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
598 {
599   REGISTER unsigned char *src;
600   REGISTER unsigned char *dest;
601   int rc,count;
602   signed short i;
603
604   count = *sz / 2;
605   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
606   else                    *sz   = 0;
607   rc      = count;
608   src     = (unsigned char *) *data;
609   *outbuf =
610   dest    = miscplay_sndbuf;
611   for (count /= 2; count--; ) {
612     i = ((int)(src[0]) +
613         256*(int)(src[1]) +
614        (int)(src[2]) +
615        256*(int)(src[3])) / 2;
616     src += 4;
617     *dest++ = (unsigned char)(i & 0xFF);
618     *dest++ = (unsigned char)((i / 256) & 0xFF); }
619   *data = src;
620   return(rc);
621 }
622
623 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
624    signed mono data */
625 size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
626 {
627   REGISTER unsigned char *src;
628   REGISTER unsigned char *dest;
629   int rc,count;
630   signed short i;
631
632   count = *sz / 2;
633   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
634   else                    *sz   = 0;
635   rc      = count;
636   src     = (unsigned char *) *data;
637   *outbuf =
638   dest    = miscplay_sndbuf;
639   for (count /= 2; count--; ) {
640     i = ((int)(src[1]) +
641         256*(int)(src[0]) +
642        (int)(src[3]) +
643        256*(int)(src[2])) / 2;
644     src += 4;
645     *dest++ = (unsigned char)((i / 256) & 0xFF);
646     *dest++ = (unsigned char)(i & 0xFF); }
647   *data = src;
648   return(rc);
649 }
650
651 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
652 size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
653 {
654   REGISTER unsigned char *src;
655   REGISTER unsigned char *dest;
656   int rc,count;
657
658   count = *sz / 2;
659   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
660   else                    *sz   = 0;
661   rc      = count;
662   src     = (unsigned char *) *data;
663   *outbuf =
664   dest    = miscplay_sndbuf;
665   while (count--) {
666     *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
667     src += 2;
668   }
669   *data = src;
670   return(rc);
671 }
672
673 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
674 size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
675 {
676   REGISTER unsigned char *src;
677   REGISTER unsigned char *dest;
678   int rc,count;
679
680   count = *sz / 2;
681   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
682   else                    *sz   = 0;
683   rc      = count;
684   src     = (unsigned char *) *data;
685   *outbuf =
686   dest    = miscplay_sndbuf;
687   while (count--) {
688     *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
689     src += 2;
690   }
691   *data = src;
692   return(rc);
693 }
694
695 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
696    mono data */
697 size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
698 {
699   REGISTER unsigned char *src;
700   REGISTER unsigned char *dest;
701   int rc,count;
702
703   count = *sz / 4;
704   if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
705   else                    *sz   = 0;
706   rc      = count;
707   src     = (unsigned char *) *data;
708   *outbuf =
709   dest    = miscplay_sndbuf;
710   while (count--) {
711     *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
712                               (int)((signed char *)src)[3]) / 2 ^ 0x80);
713     src += 4;
714   }
715   *data = src;
716   return(rc);
717 }
718
719 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
720    mono data */
721 size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
722 {
723   REGISTER unsigned char *src;
724   REGISTER unsigned char *dest;
725   int rc,count;
726
727   count = *sz / 4;
728   if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
729   else                    *sz   = 0;
730   rc      = count;
731   src     = (unsigned char *) *data;
732   *outbuf =
733   dest    = miscplay_sndbuf;
734   while (count--) {
735     *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
736                               (int)((signed char *)src)[2]) / 2 ^ 0x80);
737     src += 4;
738   }
739   *data = src;
740   return(rc);
741 }
742
743 /* Look at the header of the sound file and try to determine the format;
744    we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
745    else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
746 fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
747                              int *tracks,
748                              size_t (**parsesndfile)(void **,size_t *sz,
749                                                      void **))
750 {
751   /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
752   if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
753               (format[22]+256*format[23]) ==
754       ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
755     *fmt          = AFMT_U8;
756     *speed        = 8000;
757     *tracks       = 2;
758     *parsesndfile = parsevoc;
759     return(fmtVoc); }
760   else if (!memcmp(format,"RIFF",4) &&
761           !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
762     if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
763        memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
764       return(fmtIllegal);
765     *fmt          = (format[32]/(*tracks = format[22])) == 1 ?
766                     AFMT_U8 : AFMT_S16_LE;
767     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
768     *speed        = format[24]+256*(format[25]+256*
769                                    (format[26]+256*format[27]));
770     *parsesndfile = parsewave;
771     return(fmtWave); }
772   else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
773     if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
774       *fmt          = AFMT_MU_LAW;
775       *speed        = 8000;
776       *tracks       = 1;
777       *parsesndfile = parsesundecaudio;
778       return(fmtSunAudio); }
779     if      (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
780     else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
781     else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
782     else return(fmtIllegal);
783     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
784     *speed        = format[19]+256*(format[18]+256*
785                                    (format[17]+256*format[16]));
786     *tracks       = format[23];
787     *parsesndfile = parsesundecaudio;
788     return(fmtSunAudio); }
789   else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
790     if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
791       *fmt          = AFMT_MU_LAW;
792       *speed        = 8000;
793       *tracks       = 1;
794       *parsesndfile = parsesundecaudio;
795       return(fmtSunAudio); }
796     if      (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
797     else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
798     else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
799     else return(fmtIllegal);
800     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
801     *speed        = format[16]+256*(format[17]+256*
802                                    (format[18]+256*format[19]));
803     *tracks       = format[20];
804     *parsesndfile = parsesundecaudio;
805     return(fmtSunAudio); }
806   else {
807     *fmt          = AFMT_U8;
808     *speed        = 8000;
809     *tracks       = 1;
810     *parsesndfile = parseraw;
811     return(fmtRaw); }
812 }