Contents in 1999-06-04-13 of release-21-2.
[chise/xemacs-chise.git.1] / src / linuxplay.c
1 /* linuxplay.c - play a sound file on the speaker
2  **
3  ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
4  ** This is version 1.3 of linuxplay.c
5  **
6  ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
7  ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
8  ** information.
9  **
10  ** Permission to use, copy, modify, and distribute this software and its
11  ** documentation for any purpose and without fee is hereby granted, provided
12  ** that the above copyright notice appear in all copies and that both that
13  ** copyright notice and this permission notice appear in supporting
14  ** documentation.  This software is provided "as is" without express or
15  ** implied warranty.
16  **
17  ** Changelog:
18  **  1.0  --  first release; supports SunAudio, Wave and RAW file formats
19  **           detects (and rejects) VOC file format
20  **           tested with PC-Speaker driver only
21  **  1.1  --  fixed bug with playback of stereo Wave files
22  **           fixed VOC file detection
23  **           fixed mono/8bit conversion
24  **           cleaned up mixer programming (c.f. VoxWare-SDK)
25  **           tested with PC-Speaker driver and with PAS16 soundcard
26  **  1.2  --  first (incompatible) attempt at fixing reliable signal handling
27  **  1.3  --  changed signal handling to use reliable signals; this is done
28  **           by including "syssignal.h"; it fixes nasty program crashes
29  **           when using native sound in TTY mode.
30  **           added support for DEC audio file format (this is basically the
31  **           same as Sun audio, but uses little endian format, instead).
32  **           strip the header from Sun audio and DEC audio files in order to
33  **           prevent noise at beginning of samples (thanks to Thomas Pundt
34  **           <pundtt@math.uni-muenster.de> for pointing out this bug and
35  **           providing information on the file format).
36  **           added a few more conversion routines.
37  **           made the code even more tolerant to the limits imposed by some
38  **           soundcards and try to accept soundfiles even if they are not
39  **           fully conformant to the standard.
40  **  1.4  --  increased header size to 256; I hope there is no sample software
41  **           that requires this much.
42  **           added code for converting from signed to unsigned format as
43  **           some soundcards cannot handle signed 8bit data.
44  */
45
46 /* Synched up with: Not in FSF. */
47
48 #define HEADERSZ  256   /* has to be at least as big as the biggest header   */
49 #define SNDBUFSZ  2048  /* has to be at least as big as HEADERSZ             */
50
51 /* XEmacs beta testers say:  undef this by default. */
52 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded
53                                samples sounds very poor; possibly,
54                                this is true only for the PC-Snd
55                                driver, so undefine this symbol at your
56                                discretion */
57
58 #ifdef HAVE_CONFIG_H
59 #include <config.h>
60 #endif
61
62 #include <errno.h>
63 #include <fcntl.h>
64 #include SOUNDCARD_H_PATH /* Path computed by configure */
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <fcntl.h>
69 #include <sys/file.h>
70 #include <sys/ioctl.h>
71 #include <sys/signal.h>
72 #include <unistd.h>
73
74 #ifdef LINUXPLAYSTANDALONE
75 #define perror(str) fprintf(stderr,"audio: %s %s\n",str,strerror(errno));
76 #define warn(str)   fprintf(stderr,"audio: %s\n",str);
77 #else
78 #include "lisp.h"
79 #include "syssignal.h"
80 #include "sysfile.h"
81 #define perror(str) message("audio: %s, %s ",str,strerror(errno))
82 #define warn(str)   message("audio: %s ",GETTEXT(str))
83 #endif
84
85 #ifdef __GNUC__
86 #define UNUSED(x) ((void)(x))
87 #else
88 #define UNUSED(x)
89 #define __inline__
90 #endif
91
92 static  void (*sighup_handler)(int);
93 static  void (*sigint_handler)(int);
94
95 /* Maintain global variable for keeping parser state information; this struct
96    is set to zero before the first invocation of the parser. The use of a
97    global variable prevents multiple concurrent executions of this code, but
98    this does not happen anyways... */
99 enum wvState
100 { wvMain,
101   wvSubchunk,
102   wvOutOfBlock,
103   wvSkipChunk,
104   wvSoundChunk,
105   wvFatal,
106   wvFatalNotify
107 };
108
109 static union {
110   struct {
111     int           align;
112     enum wvState state;
113     size_t        left;
114     unsigned char leftover[HEADERSZ];
115     signed long   chunklength;
116   } wave;
117   struct {
118     int           align;
119     int           isdata;
120     int           skipping;
121     size_t        left;
122     unsigned char leftover[HEADERSZ];
123   } audio;
124 } parsestate;
125
126 /* Use a global buffer as scratch-pad for possible conversions of the
127    sampling format */
128 unsigned char linuxplay_sndbuf[SNDBUFSZ];
129
130 static int           mix_fd;
131 static int           audio_vol;
132 static int           audio_fd;
133 static char          *audio_dev = "/dev/dsp";
134
135 typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
136
137 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
138    devices before terminating sound output; this requires reliable
139    signals as provided by "syssignal.h" */
140 static void sighandler(int sig)
141 {
142   if (mix_fd > 0) {
143     if (audio_vol >= 0) {
144       ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
145       audio_vol = -1; }
146     if (mix_fd != audio_fd)
147       close(mix_fd);
148     mix_fd = -1; }
149   if (audio_fd > 0) {
150     ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
151     ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
152     close(audio_fd);
153     audio_fd = -1; }
154   if (sig == SIGHUP && sighup_handler)      sighup_handler(sig);
155   else if (sig == SIGINT && sigint_handler) sigint_handler(sig);
156   else exit(1);
157 }
158
159 /* There is no special treatment required for parsing raw data files; we
160    assume that these files contain data in 8bit unsigned format that
161    has been sampled at 8kHz; there is no extra header */
162 static size_t parseraw(void **data,size_t *sz,void **outbuf)
163 {
164   int rc = *sz;
165
166   *outbuf = *data;
167   *sz = 0;
168   return(rc);
169 }
170
171 /* Currently we cannot cope with files in VOC format; if you really need
172    to play these files, they should be converted by using SOX */
173 static size_t parsevoc(void **data,size_t *sz,void **outbuf)
174 {
175   UNUSED(data);
176   UNUSED(sz);
177   UNUSED(outbuf);
178   return(0);
179 }
180
181 /* We need to perform some look-ahead in order to parse files in WAVE format;
182    this might require re-partioning of the data segments if headers cross the
183    boundaries between two read operations. This is done in a two-step way:
184    first we request a certain amount of bytes... */
185 static __inline__ int waverequire(void **data,size_t *sz,size_t rq)
186 {
187   int rc = 1;
188
189   if (rq > HEADERSZ) {
190     warn("Header size exceeded while parsing WAVE file");
191     parsestate.wave.state = wvFatal;
192     *sz = 0;
193     return(0); }
194   if ((rq -= parsestate.wave.left) <= 0)
195     return(rc);
196   if (rq > *sz) {rq = *sz; rc = 0;}
197   memcpy(parsestate.wave.leftover+parsestate.wave.left,
198          *data,rq);
199   parsestate.wave.left      += rq;
200   (*(unsigned char **)data) += rq;
201   *sz                       -= rq;
202   return(rc);
203 }
204
205 /* ...and next we remove this many bytes from the buffer */
206 static __inline__ void waveremove(size_t rq)
207 {
208   if (parsestate.wave.left <= rq)
209     parsestate.wave.left = 0;
210   else {
211     parsestate.wave.left -= rq;
212     memmove(parsestate.wave.leftover,
213             parsestate.wave.leftover+rq,
214             parsestate.wave.left); }
215   return;
216 }
217
218 /* Sound files in WAVE format can contain an arbitrary amount of tagged
219    chunks; this requires quite some effort for parsing the data */
220 static size_t parsewave(void **data,size_t *sz,void **outbuf)
221 {
222   for (;;)
223     switch (parsestate.wave.state) {
224     case wvMain:
225       if (!waverequire(data,sz,20))
226         return(0);
227       /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
228       parsestate.wave.chunklength = parsestate.wave.leftover[16] +
229         256*(parsestate.wave.leftover[17] +
230              256*(parsestate.wave.leftover[18] +
231                   256*parsestate.wave.leftover[19]));
232       waveremove(20);
233       parsestate.wave.state = wvSubchunk;
234       break;
235     case wvSubchunk:
236       if (!waverequire(data,sz,parsestate.wave.chunklength))
237         return(0);
238       parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1
239         : parsestate.wave.leftover[12];
240       if (parsestate.wave.align != 1 &&
241           parsestate.wave.align != 2 &&
242           parsestate.wave.align != 4) {
243         warn("Illegal datawidth detected while parsing WAVE file");
244         parsestate.wave.state = wvFatal; }
245       else
246         parsestate.wave.state = wvOutOfBlock;
247       waveremove(parsestate.wave.chunklength);
248       break;
249     case wvOutOfBlock:
250       if (!waverequire(data,sz,8))
251         return(0);
252       /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
253       parsestate.wave.chunklength = parsestate.wave.leftover[4] +
254         256*(parsestate.wave.leftover[5] +
255              256*(parsestate.wave.leftover[6] +
256                   256*(parsestate.wave.leftover[7] & 0x7F)));
257       if (memcmp(parsestate.wave.leftover,"data",4))
258         parsestate.wave.state = wvSkipChunk;
259       else
260         parsestate.wave.state = wvSoundChunk;
261       waveremove(8);
262       break;
263     case wvSkipChunk:
264       if (parsestate.wave.chunklength > 0 && *sz > 0 &&
265           (signed long)*sz < (signed long)parsestate.wave.chunklength) {
266         parsestate.wave.chunklength -= *sz;
267         *sz = 0; }
268       else {
269         if (parsestate.wave.chunklength > 0 && *sz > 0) {
270           *sz -= parsestate.wave.chunklength;
271           (*(unsigned char **)data) += parsestate.wave.chunklength; }
272         parsestate.wave.state = wvOutOfBlock; }
273       break;
274     case wvSoundChunk: {
275       size_t count,rq;
276       if (parsestate.wave.left) { /* handle leftover bytes from last
277                                      alignment operation */
278         count = parsestate.wave.left;
279         rq    = HEADERSZ-count;
280         if (rq > (size_t) parsestate.wave.chunklength)
281           rq = parsestate.wave.chunklength;
282         if (!waverequire(data,sz,rq)) {
283           parsestate.wave.chunklength -= parsestate.wave.left - count;
284           return(0); }
285         parsestate.wave.chunklength -= rq;
286         *outbuf                      = parsestate.wave.leftover;
287         parsestate.wave.left         = 0;
288         return(rq); }
289       if (*sz >= (size_t) parsestate.wave.chunklength) {
290         count  = parsestate.wave.chunklength;
291         rq     = 0; }
292       else {
293         count  = *sz;
294         count -= rq = count % parsestate.wave.align; }
295       *outbuf                   = *data;
296       (*(unsigned char **)data) += count;
297       *sz                       -= count;
298       if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) {
299         parsestate.wave.state = wvOutOfBlock;
300         /* Some broken software (e.g. SOX) attaches junk to the end of a sound
301            chunk; so, let's ignore this... */
302         if (parsestate.wave.chunklength)
303           parsestate.wave.state = wvSkipChunk; }
304       else if (rq)
305         /* align data length to a multiple of datasize; keep additional data
306            in "leftover" buffer --- this is necessary to ensure proper
307            functioning of the sndcnv... routines */
308         waverequire(data,sz,rq);
309       return(count); }
310     case wvFatalNotify:
311       warn("Irrecoverable error while parsing WAVE file");
312       parsestate.wave.state = wvFatal;
313       break;
314     case wvFatal:
315     default:
316       *sz = 0;
317       return(0); }
318 }
319
320 /* Strip the header from files in Sun/DEC audio format; this requires some
321    extra processing as the header can be an arbitrary size and it might
322    result in alignment errors for subsequent conversions --- thus we do
323    some buffering, where needed */
324 static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf)
325 {
326   /* There is data left over from the last invocation of this function; join
327      it with the new data and return a sound chunk that is as big as a
328      single entry */
329   if (parsestate.audio.left) {
330     if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) {
331       int  count;
332       memmove(parsestate.audio.leftover + parsestate.audio.left,
333               *data,
334               count = parsestate.audio.align - parsestate.audio.left);
335       *outbuf = parsestate.audio.leftover;
336       *sz    -= count;
337       *data   = (*(char **)data) + count;
338       parsestate.audio.left = 0;
339       return(parsestate.audio.align); }
340     else {
341       /* We need even more data in order to get one complete single entry! */
342       memmove(parsestate.audio.leftover + parsestate.audio.left,
343               *data,
344               *sz);
345       *data = (*(char **)data) + *sz;
346       parsestate.audio.left += *sz;
347       *sz   = 0;
348       return(0); } }
349
350   /* This is the main sound chunk, strip of any extra data that does not fit
351      the alignment requirements and move these bytes into the leftover buffer*/
352   if (parsestate.audio.isdata) {
353     int rc = *sz;
354     *outbuf = *data;
355     if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
356       memmove(parsestate.audio.leftover,
357               (char *)*outbuf + rc - parsestate.audio.left,
358               parsestate.audio.left);
359       rc -= parsestate.audio.left; }
360     *sz = 0;
361     return(rc); }
362
363   /* This is the first invocation of this function; we need to parse the
364      header information and determine how many bytes we need to skip until
365      the start of the sound chunk */
366   if (!parsestate.audio.skipping) {
367     unsigned char *header = (unsigned char *) *data;
368     if (*sz < 8) {
369       warn("Irrecoverable error while parsing Sun/DEC audio file");
370       return(0); }
371     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
372     if (header[3]) { /* Sun audio (big endian) */
373       parsestate.audio.align = ((header[15] > 2)+1)*header[23];
374       parsestate.audio.skipping = header[7]+256*(header[6]+256*
375                                                  (header[5]+256*header[4])); }
376     else { /* DEC audio (little endian) */
377       parsestate.audio.align = ((header[12] > 2)+1)*header[20];
378       parsestate.audio.skipping = header[4]+256*(header[5]+256*
379                                                  (header[6]+256*header[7])); }}
380
381   /* We are skipping extra data that has been attached to header; most usually
382      this will be just a comment, such as the original filename and/or the
383      creation date. Make sure that we do not return less than one single sound
384      sample entry to the caller; if this happens, rather decide to move those
385      few bytes into the leftover buffer and deal with it later */
386   if (*sz >= (size_t) parsestate.audio.skipping) {
387     /* Skip just the header information and return the sound chunk */
388     int rc = *sz - parsestate.audio.skipping;
389     *outbuf = (char *)*data + parsestate.audio.skipping;
390     if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
391       memmove(parsestate.audio.leftover,
392               (char *)*outbuf + rc - parsestate.audio.left,
393               parsestate.audio.left);
394       rc -= parsestate.audio.left; }
395     *sz = 0;
396     parsestate.audio.skipping = 0;
397     parsestate.audio.isdata++;
398     return(rc); }
399   else {
400     /* Skip everything */
401     parsestate.audio.skipping -= *sz;
402     return(0); }
403 }
404
405 /* If the soundcard could not be set to natively support the data format, we
406    try to do some limited on-the-fly conversion to a different format; if
407    no conversion is needed, though, we can output directly */
408 static size_t sndcnvnop(void **data,size_t *sz,void **outbuf)
409 {
410   int rc = *sz;
411
412   *outbuf = *data;
413   *sz = 0;
414   return(rc);
415 }
416
417 /* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
418 static size_t sndcnv8U_2mono(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 / 2;
425   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
426   else                    *sz   = 0;
427   rc      = count;
428   src     = (unsigned char *) *data;
429   *outbuf =
430   dest    = linuxplay_sndbuf;
431   while (count--)
432     *dest++ = (unsigned char)(((int)*(src)++ +
433                                (int)*(src)++) / 2);
434   *data   = src;
435   return(rc);
436 }
437
438 /* Convert 8 bit signed stereo data to 8 bit signed mono data */
439 static size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
440 {
441   REGISTER unsigned char *src;
442   REGISTER unsigned char *dest;
443   int rc, count;
444
445   count = *sz / 2;
446   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
447   else                    *sz   = 0;
448   rc      = count;
449   src     = (unsigned char *) *data;
450   *outbuf =
451   dest    = linuxplay_sndbuf;
452   while (count--)
453     *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
454                                (int)*((signed char *)(src++))) / 2);
455   *data   = src;
456   return(rc);
457 }
458
459 /* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
460 static size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
461 {
462   REGISTER unsigned char *src;
463   REGISTER unsigned char *dest;
464   int rc,count;
465
466   count = *sz / 2;
467   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
468   else                    *sz   = 0;
469   rc      = count;
470   src     = (unsigned char *) *data;
471   *outbuf =
472   dest    = linuxplay_sndbuf;
473   while (count--)
474     *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
475                                (int)*((signed char *)(src++))) / 2) ^ 0x80;
476   *data   = src;
477   return(rc);
478 }
479
480 /* Convert 8 bit signed mono data to 8 bit unsigned mono data */
481 static size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
482 {
483   REGISTER unsigned char *src;
484   REGISTER unsigned char *dest;
485   int rc,count;
486
487   count = *sz;
488   if (count > SNDBUFSZ) { *sz  -= SNDBUFSZ; count = SNDBUFSZ; }
489   else                    *sz   = 0;
490   rc      = count;
491   src     = (unsigned char *) *data;
492   *outbuf =
493   dest    = linuxplay_sndbuf;
494   while (count--)
495     *dest++ = *(src)++ ^ 0x80;
496   *data   = src;
497   return(rc);
498 }
499
500 /* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
501    number --- I hope, I got this conversion right :-) */
502 static __inline__ signed char int2ulaw(int i)
503 {
504     /* Lookup table for fast calculation of number of bits that need shifting*/
505     static short int t_bits[128] = {
506       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,
507       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,
508       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,
509       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};
510     REGISTER int bits,logi;
511
512     /* unrolling this condition (hopefully) improves execution speed */
513     if (i < 0) {
514       if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
515       logi = (i >> ((bits = t_bits[i/256])+4));
516       return((bits << 4 | logi) ^ 0x7F); }
517     else {
518       if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
519       logi = (i >> ((bits = t_bits[i/256])+4));
520       return(~(bits << 4 | logi)); }
521 }
522
523 /* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
524 static size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
525 {
526
527   static short int ulaw2int[256] = {
528     /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
529     -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
530     -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
531      -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
532      -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
533      -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
534      -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
535      -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
536      -1438, -1374, -1310, -1246, -1182, -1118, -1054,  -990,
537       -942,  -910,  -878,  -846,  -814,  -782,  -750,  -718,
538       -686,  -654,  -622,  -590,  -558,  -526,  -494,  -462,
539       -438,  -422,  -406,  -390,  -374,  -358,  -342,  -326,
540       -310,  -294,  -278,  -262,  -246,  -230,  -214,  -198,
541       -186,  -178,  -170,  -162,  -154,  -146,  -138,  -130,
542       -122,  -114,  -106,   -98,   -90,   -82,   -74,   -66,
543        -60,   -56,   -52,   -48,   -44,   -40,   -36,   -32,
544        -28,   -24,   -20,   -16,   -12,    -8,    -4,    +0,
545     +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
546     +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
547      +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
548      +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
549      +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
550      +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
551      +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
552      +1438, +1374, +1310, +1246, +1182, +1118, +1054,  +990,
553       +942,  +910,  +878,  +846,  +814,  +782,  +750,  +718,
554       +686,  +654,  +622,  +590,  +558,  +526,  +494,  +462,
555       +438,  +422,  +406,  +390,  +374,  +358,  +342,  +326,
556       +310,  +294,  +278,  +262,  +246,  +230,  +214,  +198,
557       +186,  +178,  +170,  +162,  +154,  +146,  +138,  +130,
558       +122,  +114,  +106,   +98,   +90,   +82,   +74,   +66,
559        +60,   +56,   +52,   +48,   +44,   +40,   +36,   +32,
560        +28,   +24,   +20,   +16,   +12,    +8,    +4,    +0};
561
562   REGISTER unsigned char *src;
563   REGISTER unsigned char *dest;
564   int rc,count;
565
566   count = *sz / 2;
567   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
568   else                    *sz   = 0;
569   rc      = count;
570   src     = (unsigned char *) *data;
571   *outbuf =
572   dest    = linuxplay_sndbuf;
573   while (count--)
574     /* it is not possible to directly interpolate between two ulaw encoded
575        data bytes, thus we need to convert to linear format first and later
576        we convert back to ulaw format */
577     *dest++ = int2ulaw(ulaw2int[*(src)++] +
578                        ulaw2int[*(src)++]);
579   *data = src;
580   return(rc);
581 }
582
583 /* Convert 16 bit little endian signed stereo data to 16 bit little endian
584    signed mono data */
585 static size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
586 {
587   REGISTER unsigned char *src;
588   REGISTER unsigned char *dest;
589   int rc,count;
590   signed short i;
591
592   count = *sz / 2;
593   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
594   else                    *sz   = 0;
595   rc      = count;
596   src     = (unsigned char *) *data;
597   *outbuf =
598   dest    = linuxplay_sndbuf;
599   for (count /= 2; count--; ) {
600     i = ((int)(src[0]) +
601         256*(int)(src[1]) +
602         (int)(src[2]) +
603         256*(int)(src[3])) / 2;
604     src += 4;
605     *dest++ = (unsigned char)(i & 0xFF);
606     *dest++ = (unsigned char)((i / 256) & 0xFF); }
607   *data = src;
608   return(rc);
609 }
610
611 /* Convert 16 bit big endian signed stereo data to 16 bit big endian
612    signed mono data */
613 static size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
614 {
615   REGISTER unsigned char *src;
616   REGISTER unsigned char *dest;
617   int rc,count;
618   signed short i;
619
620   count = *sz / 2;
621   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
622   else                    *sz   = 0;
623   rc      = count;
624   src     = (unsigned char *) *data;
625   *outbuf =
626   dest    = linuxplay_sndbuf;
627   for (count /= 2; count--; ) {
628     i = ((int)(src[1]) +
629         256*(int)(src[0]) +
630         (int)(src[3]) +
631         256*(int)(src[2])) / 2;
632     src += 4;
633     *dest++ = (unsigned char)((i / 256) & 0xFF);
634     *dest++ = (unsigned char)(i & 0xFF); }
635   *data = src;
636   return(rc);
637 }
638
639 /* Convert 16 bit little endian signed data to 8 bit unsigned data */
640 static size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
641 {
642   REGISTER unsigned char *src;
643   REGISTER unsigned char *dest;
644   int rc,count;
645
646   count = *sz / 2;
647   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
648   else                    *sz   = 0;
649   rc      = count;
650   src     = (unsigned char *) *data;
651   *outbuf =
652   dest    = linuxplay_sndbuf;
653   while (count--) {
654     *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
655     src += 2;
656   }
657   *data = src;
658   return(rc);
659 }
660
661 /* Convert 16 bit big endian signed data to 8 bit unsigned data */
662 static size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
663 {
664   REGISTER unsigned char *src;
665   REGISTER unsigned char *dest;
666   int rc,count;
667
668   count = *sz / 2;
669   if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
670   else                    *sz   = 0;
671   rc      = count;
672   src     = (unsigned char *) *data;
673   *outbuf =
674   dest    = linuxplay_sndbuf;
675   while (count--) {
676     *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
677     src += 2;
678   }
679   *data = src;
680   return(rc);
681 }
682
683 /* Convert 16 bit little endian signed stereo data to 8 bit unsigned
684    mono data */
685 static size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
686 {
687   REGISTER unsigned char *src;
688   REGISTER unsigned char *dest;
689   int rc,count;
690
691   count = *sz / 4;
692   if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
693   else                    *sz   = 0;
694   rc      = count;
695   src     = (unsigned char *) *data;
696   *outbuf =
697   dest    = linuxplay_sndbuf;
698   while (count--) {
699     *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
700                                (int)((signed char *)src)[3]) / 2 ^ 0x80);
701     src += 4;
702   }
703   *data = src;
704   return(rc);
705 }
706
707 /* Convert 16 bit big endian signed stereo data to 8 bit unsigned
708    mono data */
709 static size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
710 {
711   REGISTER unsigned char *src;
712   REGISTER unsigned char *dest;
713   int rc,count;
714
715   count = *sz / 4;
716   if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
717   else                    *sz   = 0;
718   rc      = count;
719   src     = (unsigned char *) *data;
720   *outbuf =
721   dest    = linuxplay_sndbuf;
722   while (count--) {
723     *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
724                                (int)((signed char *)src)[2]) / 2 ^ 0x80);
725     src += 4;
726   }
727   *data = src;
728   return(rc);
729 }
730
731 /* Look at the header of the sound file and try to determine the format;
732    we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
733    else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
734 static fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
735                               int *tracks,
736                               size_t (**parsesndfile)(void **,size_t *sz,
737                                                       void **))
738 {
739   /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
740   if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
741               (format[22]+256*format[23]) ==
742       ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
743     *fmt          = AFMT_U8;
744     *speed        = 8000;
745     *tracks       = 2;
746     *parsesndfile = parsevoc;
747     return(fmtVoc); }
748   else if (!memcmp(format,"RIFF",4) &&
749            !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
750     if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
751         memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
752       return(fmtIllegal);
753     *fmt          = (format[32]/(*tracks = format[22])) == 1 ?
754                     AFMT_U8 : AFMT_S16_LE;
755     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
756     *speed        = format[24]+256*(format[25]+256*
757                                     (format[26]+256*format[27]));
758     *parsesndfile = parsewave;
759     return(fmtWave); }
760   else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
761     if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
762       *fmt          = AFMT_MU_LAW;
763       *speed        = 8000;
764       *tracks       = 1;
765       *parsesndfile = parsesundecaudio;
766       return(fmtSunAudio); }
767     if      (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
768     else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
769     else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
770     else return(fmtIllegal);
771     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
772     *speed        = format[19]+256*(format[18]+256*
773                                     (format[17]+256*format[16]));
774     *tracks       = format[23];
775     *parsesndfile = parsesundecaudio;
776     return(fmtSunAudio); }
777   else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
778     if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
779       *fmt          = AFMT_MU_LAW;
780       *speed        = 8000;
781       *tracks       = 1;
782       *parsesndfile = parsesundecaudio;
783       return(fmtSunAudio); }
784     if      (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
785     else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
786     else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
787     else return(fmtIllegal);
788     /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
789     *speed        = format[16]+256*(format[17]+256*
790                                     (format[18]+256*format[19]));
791     *tracks       = format[20];
792     *parsesndfile = parsesundecaudio;
793     return(fmtSunAudio); }
794   else {
795     *fmt          = AFMT_U8;
796     *speed        = 8000;
797     *tracks       = 1;
798     *parsesndfile = parseraw;
799     return(fmtRaw); }
800 }
801
802 /* Initialize the soundcard and mixer device with the parameters that we
803    found in the header of the sound file. If the soundcard is not capable of
804    natively supporting the required parameters, then try to set up conversion
805    routines.
806    The difficulty with setting up the sound card is that the parameters are
807    not fully orthogonal; changing one of them might affect some of the
808    others, too. Thus we do quite a lot of double checking; actually most of
809    this is not needed right now, but it will come in handy, if the kernel's
810    sounddriver ever changes or if third-party sounddrivers are used. */
811 static int audio_init(int mixx_fd, int auddio_fd, int fmt, int speed,
812                       int tracks, int *volume,
813                       size_t (**sndcnv) (void **, size_t *sz, void **))
814 {
815   int i,the_speed,the_stereo,the_fmt;
816
817   *sndcnv = sndcnvnop;
818
819   if (ioctl(auddio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
820     perror("SNDCTL_DSP_SYNC");
821     return(0); }
822
823   /* Initialize sound hardware with preferred parameters */
824
825   /* If the sound hardware cannot support 16 bit format or requires a
826      different byte sex then try to drop to 8 bit format */
827
828   the_fmt = fmt;
829   if(ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0) {
830         perror("SNDCTL_DSP_SETFMT");
831         return(0);
832   }
833
834   if (fmt != the_fmt) {
835     if (fmt == AFMT_S16_LE || fmt == AFMT_S16_BE) {
836       *sndcnv = fmt == AFMT_S16_BE ? sndcnv2byteBE : sndcnv2byteLE;
837       if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
838           fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
839           fmt != the_fmt) {
840         perror("SNDCTL_DSP_SETFMT");
841         return(0); } }
842     else if (fmt == AFMT_MU_LAW && the_fmt == AFMT_U8 ) {
843       /* the kernel will convert for us */ }
844     else {
845       perror("SNDCTL_DSP_SETFMT");
846       return(0); } }
847   else if (fmt == AFMT_S8) {
848     *sndcnv = sndcnv2unsigned;
849     if (((i=fmt=AFMT_U8),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
850         fmt != i || ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt) < 0 ||
851         fmt != the_fmt) {
852       perror("SNDCTRL_DSP_SETFMT");
853       return(0); } }
854
855   /* The PCSP driver does not support reading of the sampling rate via the
856      SOUND_PCM_READ_RATE ioctl; determine "the_speed" here */
857   the_speed = speed; ioctl(audio_fd,SNDCTL_DSP_SPEED,&the_speed);
858   /* The PCSP driver does not support reading of the mono/stereo flag, thus
859      we assume, that failure to change this mode means we are in mono mode  */
860   if (((i = (the_stereo = tracks)-1),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0)
861     the_stereo = 1;
862
863   /* Try to request stereo playback (if needed); if this cannot be supported
864      by the hardware, then install conversion routines for mono playback */
865
866   /* This ioctl will fail if we use the PCSP driver; thus the value of
867      "the_stereo" is still unchanged */
868   ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
869   if (tracks != the_stereo) {
870     if (tracks == 2) {
871       tracks = 1;
872       *sndcnv = *sndcnv == sndcnv2byteLE   ? sndcnv2monobyteLE :
873               *sndcnv == sndcnv2byteBE   ? sndcnv2monobyteBE :
874               *sndcnv == sndcnv2unsigned ? sndcnv2monounsigned :
875         the_fmt == AFMT_S16_LE ? sndcnv16_2monoLE :
876         the_fmt == AFMT_S16_BE ? sndcnv16_2monoBE :
877         the_fmt == AFMT_S8     ? sndcnv8S_2mono :
878         the_fmt == AFMT_U8     ? sndcnv8U_2mono :
879         the_fmt == AFMT_MU_LAW ? sndcnvULaw_2mono : NULL;
880       if (*sndcnv == NULL) { /* this should not happen */
881         perror("SNDCTL_DSP_STEREO");
882         return(0); }
883       /* Switch to mono mode */
884       if (((i = 0),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i)) < 0 || i) {
885         perror("SNDCTL_DSP_STEREO");
886         return(0); }
887       /* Now double check that everything is set as expected */
888       if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
889           (i != the_fmt &&
890            (((i=the_fmt),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
891             i != the_fmt ||
892             ((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
893             i != the_fmt)) ||
894           (ioctl(audio_fd,SOUND_PCM_READ_CHANNELS,&i) >= 0 &&
895            i != 1)) {
896         /* There was no way that we could set the soundcard to a meaningful
897            mode */
898         perror("SNDCTL_DSP_SETFMT and SNDCTL_DSP_STEREO");
899         return(0); } }
900     else {
901       /* Somebody set the soundcard to stereo even though we requested
902          mono; this should not happen... */
903       if (((i = the_stereo = tracks),ioctl(audio_fd,SNDCTL_DSP_STEREO,&i))<0 ||
904           i != the_stereo-1) {
905         perror("SNDCTL_DSP_STEREO");
906         return(0); }
907       if (((i = AFMT_QUERY),ioctl(audio_fd,SNDCTL_DSP_SETFMT,&i)) < 0 ||
908           i != the_fmt) {
909         perror("SNDCTL_DSP_SETFMT");
910         return(0); } } }
911
912   /* Fail if deviations from desired sampling frequency are too big */
913
914   /* This ioctl will fail if we use the PCSP driver; thus the value of
915      "the_speed" is still unchanged */
916   ioctl(audio_fd,SOUND_PCM_READ_RATE,&the_speed);
917   if (speed*14 < the_speed*10 || speed*6 > the_speed*10) {
918     char buffer[256];
919     sprintf(buffer,"SNDCTL_DSP_SPEED (req: %d, rtn: %d)",speed,the_speed);
920     perror(buffer);
921     return(0); }
922
923   /* Use the mixer device for setting the playback volume */
924   if (mixx_fd > 0) {
925     int vol = *volume & 0xFF;
926     if (ioctl(mixx_fd,SOUND_MIXER_READ_PCM,volume) < 0)
927       *volume = -1;
928     if (vol < 0) vol = 0; else if (vol > 100) vol = 100;
929 #ifdef NOVOLUMECTRLFORMULAW
930     if (fmt == AFMT_MU_LAW)
931       vol = 100;
932 #endif
933     vol |= 256*vol;
934     /* Do not signal an error, if volume control is unavailable! */
935     ioctl(mixx_fd,SOUND_MIXER_WRITE_PCM,&vol); }
936
937 #if defined(LINUXPLAYSTANDALONE) && 1
938   /* Debugging output is displayed only when compiled as stand-alone version */
939   {int the_volume;
940   the_fmt = AFMT_QUERY;
941   ioctl(audio_fd,SNDCTL_DSP_SETFMT,&the_fmt);
942   ioctl(auddio_fd,SOUND_PCM_READ_CHANNELS,&the_stereo);
943   ioctl(auddio_fd,SOUND_PCM_READ_RATE,&the_speed);
944   ioctl(mixx_fd,SOUND_MIXER_READ_PCM,&the_volume);
945   fprintf(stderr,"%s, %s, %dHz, L:%d/R:%d\n",
946           the_fmt == AFMT_MU_LAW ? "AFMT_MU_LAW" :
947           the_fmt == AFMT_A_LAW ? "AFMT_A_LAW" :
948           the_fmt == AFMT_IMA_ADPCM ? "AFMT_IMA_ADPCM" :
949           the_fmt == AFMT_U8 ? "AFMT_U8" :
950           the_fmt == AFMT_S16_LE ? "AFMT_S16_LE" :
951           the_fmt == AFMT_S16_BE ? "AFMT_S16_BE" :
952           the_fmt == AFMT_S8 ? "AFMT_S8" :
953           the_fmt == AFMT_U16_LE ? "AFMT_U16_LE" :
954           the_fmt == AFMT_U16_BE ? "AFMT_U16_BE" :
955           the_fmt == AFMT_MPEG ? "AFMT_MPEG" :
956           "AFMT_???",
957           the_stereo == 2 ? "stereo" : "mono",
958           the_speed,
959           the_volume / 256, the_volume % 256); }
960 #endif
961
962   return(1);
963 }
964
965 /* XEmacs requires code both for playback of pre-loaded data and for playback
966    from a soundfile; we use one function for both cases */
967 static void linux_play_data_or_file(int fd,unsigned char *data,
968                                     int length,int volume)
969 {
970   size_t         (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
971   size_t         (*sndcnv)(void **dayta,size_t *sz,void **);
972   fmtType        ffmt;
973   int            fmt,speed,tracks;
974   unsigned char *pptr,*optr,*cptr,*sptr;
975   int            wrtn,rrtn,crtn,prtn;
976
977   /* We need to read at least the header information before we can start
978      doing anything */
979   if (!data || length < HEADERSZ) {
980     if (fd < 0) return;
981     else {
982       length = read(fd,linuxplay_sndbuf,SNDBUFSZ);
983       if (length < HEADERSZ)
984         return;
985       data   = linuxplay_sndbuf;
986       length = SNDBUFSZ; }
987   }
988
989   ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
990
991   if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
992     warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)");
993       return; }
994
995   /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and
996      properly initializing it via ioctl() is preferred */
997   if ((audio_fd=open(audio_dev, O_WRONLY | O_NONBLOCK, 0)) < 0) {
998     perror(audio_dev);
999     if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; }
1000     return; }
1001
1002   /* The VoxWare-SDK discourages direct manipulation of the mixer device as
1003      this could lead to problems, when multiple sound cards are installed */
1004   mix_fd = audio_fd;
1005
1006   sighup_handler = signal(SIGHUP, sighandler);
1007   sigint_handler = signal(SIGINT, sighandler);
1008
1009   if (!audio_init(mix_fd,audio_fd,fmt,speed,tracks,&volume,&sndcnv))
1010     goto END_OF_PLAY;
1011   audio_vol = volume;
1012
1013   /* Initialize global parser state information to zero */
1014   memset(&parsestate,0,sizeof(parsestate));
1015
1016   /* Mainloop: read a block of data, parse its contents, perform all
1017                the necessary conversions and output it to the sound
1018                device; repeat until all data has been processed */
1019   rrtn = length;
1020   do {
1021     for (pptr = data; (prtn = parsesndfile((void **)&pptr,(size_t *)&rrtn,
1022                                            (void **)&optr)) > 0; )
1023       for (cptr = optr; (crtn = sndcnv((void **)&cptr,(size_t *) &prtn,
1024                                        (void **)&sptr)) > 0; ) {
1025         for (;;) {
1026           if ((wrtn = write(audio_fd,sptr,crtn)) < 0) {
1027             perror("write"); goto END_OF_PLAY; }
1028           else if (wrtn) break;
1029           else if (ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL) < 0) {
1030             perror("SNDCTL_DSP_SYNC"); goto END_OF_PLAY; } }
1031         if (wrtn != crtn) {
1032           char buf[255];
1033           sprintf(buf,"play: crtn = %d, wrtn = %d",crtn,wrtn);
1034           warn(buf);
1035           goto END_OF_PLAY; } }
1036     if (fd >= 0) {
1037       if ((rrtn = read(fd,linuxplay_sndbuf,SNDBUFSZ)) < 0) {
1038         perror("read"); goto END_OF_PLAY; } }
1039     else
1040       break;
1041   } while (rrtn > 0);
1042
1043   /* Verify that we could fully parse the entire soundfile; this is needed
1044      only for files in WAVE format */
1045   if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock &&
1046       parsestate.wave.state != wvFatal)
1047     warn("Unexpected end of WAVE file");
1048
1049 END_OF_PLAY:
1050   /* Now cleanup all used resources */
1051
1052   ioctl(audio_fd,SNDCTL_DSP_SYNC,NULL);
1053   ioctl(audio_fd,SNDCTL_DSP_RESET,NULL);
1054
1055   signal(SIGHUP,sighup_handler);
1056   signal(SIGINT,sigint_handler);
1057
1058   if (mix_fd > 0) {
1059     if (audio_vol >= 0) {
1060       ioctl(mix_fd,SOUND_MIXER_WRITE_PCM,&audio_vol);
1061       audio_vol = -1; }
1062     if (mix_fd != audio_fd)
1063       close(mix_fd);
1064     mix_fd = -1; }
1065
1066   close(audio_fd);
1067   audio_fd = -1;
1068
1069   return;
1070 }
1071
1072 /* Call "linux_play_data_or_file" with the appropriate parameters for
1073    playing a soundfile */
1074 void play_sound_file (char *sound_file, int volume);
1075 void play_sound_file (char *sound_file, int volume)
1076 {
1077   int fd;
1078
1079   if ((fd=open(sound_file,O_RDONLY,0)) < 0) {
1080     perror(sound_file);
1081     return; }
1082   linux_play_data_or_file(fd,NULL,0,volume);
1083   close(fd);
1084   return;
1085 }
1086
1087 /* Call "linux_play_data_or_file" with the appropriate parameters for
1088    playing pre-loaded data */
1089 void play_sound_data (unsigned char *data, int length, int volume);
1090 void play_sound_data (unsigned char *data, int length, int volume)
1091 {
1092   linux_play_data_or_file(-1,data,length,volume);
1093   return;
1094 }