(U-0002195D): Add `ideographic-structure'; add `sound@ja/on'; add
[chise/xemacs-chise.git.1] / src / linuxplay.c
index f5fe236..4108a19 100644 (file)
@@ -1,7 +1,8 @@
 /* linuxplay.c - play a sound file on the speaker
  **
  ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
- ** This is version 1.3 of linuxplay.c
+ ** This is version 1.3 of linuxplay.c, with platform-independent functions
+ ** moved to a different file by Robert Bihlmeyer <robbe@orcus.priv.at>.
  **
  ** Parts of this code were inspired by sunplay.c, which is copyright 1989 by
  ** Jef Poskanzer and 1991,92 by Jamie Zawinski; c.f. sunplay.c for further
@@ -45,9 +46,6 @@
 
 /* Synched up with: Not in FSF. */
 
-#define HEADERSZ  256   /* has to be at least as big as the biggest header   */
-#define SNDBUFSZ  2048  /* has to be at least as big as HEADERSZ             */
-
 /* XEmacs beta testers say:  undef this by default. */
 #undef NOVOLUMECTRLFORMULAW /* Changing the volume for uLaw-encoded
                               samples sounds very poor; possibly,
 #include <config.h>
 #endif
 
+#include "miscplay.h"
+#include "nativesound.h"
+
 #include <errno.h>
 #include <fcntl.h>
-#include SOUNDCARD_H_PATH /* Path computed by configure */
+#include SOUNDCARD_H_FILE /* Path computed by configure */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #define warn(str)   message("audio: %s ",GETTEXT(str))
 #endif
 
-#ifdef __GNUC__
-#define UNUSED(x) ((void)(x))
-#else
-#define UNUSED(x)
-#define __inline__
-#endif
-
-static  void (*sighup_handler)(int);
-static  void (*sigint_handler)(int);
-
-/* Maintain global variable for keeping parser state information; this struct
-   is set to zero before the first invocation of the parser. The use of a
-   global variable prevents multiple concurrent executions of this code, but
-   this does not happen anyways... */
-enum wvState
-{ wvMain,
-  wvSubchunk,
-  wvOutOfBlock,
-  wvSkipChunk,
-  wvSoundChunk,
-  wvFatal,
-  wvFatalNotify
-};
-
-static union {
-  struct {
-    int           align;
-    enum wvState state;
-    size_t        left;
-    unsigned char leftover[HEADERSZ];
-    signed long   chunklength;
-  } wave;
-  struct {
-    int           align;
-    int           isdata;
-    int           skipping;
-    size_t        left;
-    unsigned char leftover[HEADERSZ];
-  } audio;
-} parsestate;
-
-/* Use a global buffer as scratch-pad for possible conversions of the
-   sampling format */
-unsigned char linuxplay_sndbuf[SNDBUFSZ];
+static  SIGTYPE (*sighup_handler) (int);
+static  SIGTYPE (*sigint_handler) (int);
 
 static int           mix_fd;
 static int           audio_vol;
 static int           audio_fd;
 static char         *audio_dev = "/dev/dsp";
 
-typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
-
 /* Intercept SIGINT and SIGHUP in order to close the audio and mixer
    devices before terminating sound output; this requires reliable
    signals as provided by "syssignal.h" */
-static void sighandler(int sig)
+static SIGTYPE
+sighandler (int sig)
 {
   if (mix_fd > 0) {
     if (audio_vol >= 0) {
@@ -156,649 +114,6 @@ static void sighandler(int sig)
   else exit(1);
 }
 
-/* There is no special treatment required for parsing raw data files; we
-   assume that these files contain data in 8bit unsigned format that
-   has been sampled at 8kHz; there is no extra header */
-static size_t parseraw(void **data,size_t *sz,void **outbuf)
-{
-  int rc = *sz;
-
-  *outbuf = *data;
-  *sz = 0;
-  return(rc);
-}
-
-/* Currently we cannot cope with files in VOC format; if you really need
-   to play these files, they should be converted by using SOX */
-static size_t parsevoc(void **data,size_t *sz,void **outbuf)
-{
-  UNUSED(data);
-  UNUSED(sz);
-  UNUSED(outbuf);
-  return(0);
-}
-
-/* We need to perform some look-ahead in order to parse files in WAVE format;
-   this might require re-partioning of the data segments if headers cross the
-   boundaries between two read operations. This is done in a two-step way:
-   first we request a certain amount of bytes... */
-static __inline__ int waverequire(void **data,size_t *sz,size_t rq)
-{
-  int rc = 1;
-
-  if (rq > HEADERSZ) {
-    warn("Header size exceeded while parsing WAVE file");
-    parsestate.wave.state = wvFatal;
-    *sz = 0;
-    return(0); }
-  if ((rq -= parsestate.wave.left) <= 0)
-    return(rc);
-  if (rq > *sz) {rq = *sz; rc = 0;}
-  memcpy(parsestate.wave.leftover+parsestate.wave.left,
-        *data,rq);
-  parsestate.wave.left      += rq;
-  (*(unsigned char **)data) += rq;
-  *sz                       -= rq;
-  return(rc);
-}
-
-/* ...and next we remove this many bytes from the buffer */
-static __inline__ void waveremove(size_t rq)
-{
-  if (parsestate.wave.left <= rq)
-    parsestate.wave.left = 0;
-  else {
-    parsestate.wave.left -= rq;
-    memmove(parsestate.wave.leftover,
-           parsestate.wave.leftover+rq,
-           parsestate.wave.left); }
-  return;
-}
-
-/* Sound files in WAVE format can contain an arbitrary amount of tagged
-   chunks; this requires quite some effort for parsing the data */
-static size_t parsewave(void **data,size_t *sz,void **outbuf)
-{
-  for (;;)
-    switch (parsestate.wave.state) {
-    case wvMain:
-      if (!waverequire(data,sz,20))
-       return(0);
-      /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-      parsestate.wave.chunklength = parsestate.wave.leftover[16] +
-       256*(parsestate.wave.leftover[17] +
-            256*(parsestate.wave.leftover[18] +
-                 256*parsestate.wave.leftover[19]));
-      waveremove(20);
-      parsestate.wave.state = wvSubchunk;
-      break;
-    case wvSubchunk:
-      if (!waverequire(data,sz,parsestate.wave.chunklength))
-       return(0);
-      parsestate.wave.align = parsestate.wave.chunklength < 14 ? 1
-       : parsestate.wave.leftover[12];
-      if (parsestate.wave.align != 1 &&
-         parsestate.wave.align != 2 &&
-         parsestate.wave.align != 4) {
-       warn("Illegal datawidth detected while parsing WAVE file");
-       parsestate.wave.state = wvFatal; }
-      else
-       parsestate.wave.state = wvOutOfBlock;
-      waveremove(parsestate.wave.chunklength);
-      break;
-    case wvOutOfBlock:
-      if (!waverequire(data,sz,8))
-       return(0);
-      /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-      parsestate.wave.chunklength = parsestate.wave.leftover[4] +
-       256*(parsestate.wave.leftover[5] +
-            256*(parsestate.wave.leftover[6] +
-                 256*(parsestate.wave.leftover[7] & 0x7F)));
-      if (memcmp(parsestate.wave.leftover,"data",4))
-       parsestate.wave.state = wvSkipChunk;
-      else
-       parsestate.wave.state = wvSoundChunk;
-      waveremove(8);
-      break;
-    case wvSkipChunk:
-      if (parsestate.wave.chunklength > 0 && *sz > 0 &&
-         (signed long)*sz < (signed long)parsestate.wave.chunklength) {
-       parsestate.wave.chunklength -= *sz;
-       *sz = 0; }
-      else {
-       if (parsestate.wave.chunklength > 0 && *sz > 0) {
-         *sz -= parsestate.wave.chunklength;
-         (*(unsigned char **)data) += parsestate.wave.chunklength; }
-       parsestate.wave.state = wvOutOfBlock; }
-      break;
-    case wvSoundChunk: {
-      size_t count,rq;
-      if (parsestate.wave.left) { /* handle leftover bytes from last
-                                    alignment operation */
-       count = parsestate.wave.left;
-       rq    = HEADERSZ-count;
-       if (rq > (size_t) parsestate.wave.chunklength)
-         rq = parsestate.wave.chunklength;
-       if (!waverequire(data,sz,rq)) {
-         parsestate.wave.chunklength -= parsestate.wave.left - count;
-         return(0); }
-       parsestate.wave.chunklength -= rq;
-       *outbuf                      = parsestate.wave.leftover;
-       parsestate.wave.left         = 0;
-       return(rq); }
-      if (*sz >= (size_t) parsestate.wave.chunklength) {
-       count  = parsestate.wave.chunklength;
-       rq     = 0; }
-      else {
-       count  = *sz;
-       count -= rq = count % parsestate.wave.align; }
-      *outbuf                   = *data;
-      (*(unsigned char **)data) += count;
-      *sz                       -= count;
-      if ((parsestate.wave.chunklength -= count) < parsestate.wave.align) {
-       parsestate.wave.state = wvOutOfBlock;
-       /* Some broken software (e.g. SOX) attaches junk to the end of a sound
-          chunk; so, let's ignore this... */
-       if (parsestate.wave.chunklength)
-         parsestate.wave.state = wvSkipChunk; }
-      else if (rq)
-       /* align data length to a multiple of datasize; keep additional data
-          in "leftover" buffer --- this is necessary to ensure proper
-          functioning of the sndcnv... routines */
-       waverequire(data,sz,rq);
-      return(count); }
-    case wvFatalNotify:
-      warn("Irrecoverable error while parsing WAVE file");
-      parsestate.wave.state = wvFatal;
-      break;
-    case wvFatal:
-    default:
-      *sz = 0;
-      return(0); }
-}
-
-/* Strip the header from files in Sun/DEC audio format; this requires some
-   extra processing as the header can be an arbitrary size and it might
-   result in alignment errors for subsequent conversions --- thus we do
-   some buffering, where needed */
-static size_t parsesundecaudio(void **data,size_t *sz,void **outbuf)
-{
-  /* There is data left over from the last invocation of this function; join
-     it with the new data and return a sound chunk that is as big as a
-     single entry */
-  if (parsestate.audio.left) {
-    if (parsestate.audio.left + *sz > (size_t) parsestate.audio.align) {
-      int  count;
-      memmove(parsestate.audio.leftover + parsestate.audio.left,
-             *data,
-             count = parsestate.audio.align - parsestate.audio.left);
-      *outbuf = parsestate.audio.leftover;
-      *sz    -= count;
-      *data   = (*(char **)data) + count;
-      parsestate.audio.left = 0;
-      return(parsestate.audio.align); }
-    else {
-      /* We need even more data in order to get one complete single entry! */
-      memmove(parsestate.audio.leftover + parsestate.audio.left,
-             *data,
-             *sz);
-      *data = (*(char **)data) + *sz;
-      parsestate.audio.left += *sz;
-      *sz   = 0;
-      return(0); } }
-
-  /* This is the main sound chunk, strip of any extra data that does not fit
-     the alignment requirements and move these bytes into the leftover buffer*/
-  if (parsestate.audio.isdata) {
-    int rc = *sz;
-    *outbuf = *data;
-    if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
-      memmove(parsestate.audio.leftover,
-             (char *)*outbuf + rc - parsestate.audio.left,
-             parsestate.audio.left);
-      rc -= parsestate.audio.left; }
-    *sz = 0;
-    return(rc); }
-
-  /* This is the first invocation of this function; we need to parse the
-     header information and determine how many bytes we need to skip until
-     the start of the sound chunk */
-  if (!parsestate.audio.skipping) {
-    unsigned char *header = (unsigned char *) *data;
-    if (*sz < 8) {
-      warn("Irrecoverable error while parsing Sun/DEC audio file");
-      return(0); }
-    /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-    if (header[3]) { /* Sun audio (big endian) */
-      parsestate.audio.align = ((header[15] > 2)+1)*header[23];
-      parsestate.audio.skipping = header[7]+256*(header[6]+256*
-                                                (header[5]+256*header[4])); }
-    else { /* DEC audio (little endian) */
-      parsestate.audio.align = ((header[12] > 2)+1)*header[20];
-      parsestate.audio.skipping = header[4]+256*(header[5]+256*
-                                                (header[6]+256*header[7])); }}
-
-  /* We are skipping extra data that has been attached to header; most usually
-     this will be just a comment, such as the original filename and/or the
-     creation date. Make sure that we do not return less than one single sound
-     sample entry to the caller; if this happens, rather decide to move those
-     few bytes into the leftover buffer and deal with it later */
-  if (*sz >= (size_t) parsestate.audio.skipping) {
-    /* Skip just the header information and return the sound chunk */
-    int rc = *sz - parsestate.audio.skipping;
-    *outbuf = (char *)*data + parsestate.audio.skipping;
-    if ((parsestate.audio.left = rc % parsestate.audio.align) != 0) {
-      memmove(parsestate.audio.leftover,
-             (char *)*outbuf + rc - parsestate.audio.left,
-             parsestate.audio.left);
-      rc -= parsestate.audio.left; }
-    *sz = 0;
-    parsestate.audio.skipping = 0;
-    parsestate.audio.isdata++;
-    return(rc); }
-  else {
-    /* Skip everything */
-    parsestate.audio.skipping -= *sz;
-    return(0); }
-}
-
-/* If the soundcard could not be set to natively support the data format, we
-   try to do some limited on-the-fly conversion to a different format; if
-   no conversion is needed, though, we can output directly */
-static size_t sndcnvnop(void **data,size_t *sz,void **outbuf)
-{
-  int rc = *sz;
-
-  *outbuf = *data;
-  *sz = 0;
-  return(rc);
-}
-
-/* Convert 8 bit unsigned stereo data to 8 bit unsigned mono data */
-static size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--)
-    *dest++ = (unsigned char)(((int)*(src)++ +
-                              (int)*(src)++) / 2);
-  *data   = src;
-  return(rc);
-}
-
-/* Convert 8 bit signed stereo data to 8 bit signed mono data */
-static size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc, count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--)
-    *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
-                              (int)*((signed char *)(src++))) / 2);
-  *data   = src;
-  return(rc);
-}
-
-/* Convert 8 bit signed stereo data to 8 bit unsigned mono data */
-static size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--)
-    *dest++ = (unsigned char)(((int)*((signed char *)(src++)) +
-                              (int)*((signed char *)(src++))) / 2) ^ 0x80;
-  *data   = src;
-  return(rc);
-}
-
-/* Convert 8 bit signed mono data to 8 bit unsigned mono data */
-static size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz;
-  if (count > SNDBUFSZ) { *sz  -= SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--)
-    *dest++ = *(src)++ ^ 0x80;
-  *data   = src;
-  return(rc);
-}
-
-/* Convert a number in the range -32768..32767 to an 8 bit ulaw encoded
-   number --- I hope, I got this conversion right :-) */
-static __inline__ signed char int2ulaw(int i)
-{
-    /* Lookup table for fast calculation of number of bits that need shifting*/
-    static short int t_bits[128] = {
-      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,
-      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,
-      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,
-      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};
-    REGISTER int bits,logi;
-
-    /* unrolling this condition (hopefully) improves execution speed */
-    if (i < 0) {
-      if ((i = (132-i)) > 0x7FFF) i = 0x7FFF;
-      logi = (i >> ((bits = t_bits[i/256])+4));
-      return((bits << 4 | logi) ^ 0x7F); }
-    else {
-      if ((i = 132+i) > 0x7FFF) i = 0x7FFF;
-      logi = (i >> ((bits = t_bits[i/256])+4));
-      return(~(bits << 4 | logi)); }
-}
-
-/* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
-static size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf)
-{
-
-  static short int ulaw2int[256] = {
-    /* Precomputed lookup table for conversion from ulaw to 15 bit signed */
-    -16062,-15550,-15038,-14526,-14014,-13502,-12990,-12478,
-    -11966,-11454,-10942,-10430, -9918, -9406, -8894, -8382,
-     -7998, -7742, -7486, -7230, -6974, -6718, -6462, -6206,
-     -5950, -5694, -5438, -5182, -4926, -4670, -4414, -4158,
-     -3966, -3838, -3710, -3582, -3454, -3326, -3198, -3070,
-     -2942, -2814, -2686, -2558, -2430, -2302, -2174, -2046,
-     -1950, -1886, -1822, -1758, -1694, -1630, -1566, -1502,
-     -1438, -1374, -1310, -1246, -1182, -1118, -1054,  -990,
-      -942,  -910,  -878,  -846,  -814,  -782,  -750,  -718,
-      -686,  -654,  -622,  -590,  -558,  -526,  -494,  -462,
-      -438,  -422,  -406,  -390,  -374,  -358,  -342,  -326,
-      -310,  -294,  -278,  -262,  -246,  -230,  -214,  -198,
-      -186,  -178,  -170,  -162,  -154,  -146,  -138,  -130,
-      -122,  -114,  -106,   -98,   -90,   -82,   -74,   -66,
-       -60,   -56,   -52,   -48,   -44,   -40,   -36,   -32,
-       -28,   -24,   -20,   -16,   -12,    -8,    -4,    +0,
-    +16062,+15550,+15038,+14526,+14014,+13502,+12990,+12478,
-    +11966,+11454,+10942,+10430, +9918, +9406, +8894, +8382,
-     +7998, +7742, +7486, +7230, +6974, +6718, +6462, +6206,
-     +5950, +5694, +5438, +5182, +4926, +4670, +4414, +4158,
-     +3966, +3838, +3710, +3582, +3454, +3326, +3198, +3070,
-     +2942, +2814, +2686, +2558, +2430, +2302, +2174, +2046,
-     +1950, +1886, +1822, +1758, +1694, +1630, +1566, +1502,
-     +1438, +1374, +1310, +1246, +1182, +1118, +1054,  +990,
-      +942,  +910,  +878,  +846,  +814,  +782,  +750,  +718,
-      +686,  +654,  +622,  +590,  +558,  +526,  +494,  +462,
-      +438,  +422,  +406,  +390,  +374,  +358,  +342,  +326,
-      +310,  +294,  +278,  +262,  +246,  +230,  +214,  +198,
-      +186,  +178,  +170,  +162,  +154,  +146,  +138,  +130,
-      +122,  +114,  +106,   +98,   +90,   +82,   +74,   +66,
-       +60,   +56,   +52,   +48,   +44,   +40,   +36,   +32,
-       +28,   +24,   +20,   +16,   +12,    +8,    +4,    +0};
-
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--)
-    /* it is not possible to directly interpolate between two ulaw encoded
-       data bytes, thus we need to convert to linear format first and later
-       we convert back to ulaw format */
-    *dest++ = int2ulaw(ulaw2int[*(src)++] +
-                      ulaw2int[*(src)++]);
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit little endian signed stereo data to 16 bit little endian
-   signed mono data */
-static size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-  signed short i;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  for (count /= 2; count--; ) {
-    i = ((int)(src[0]) +
-        256*(int)(src[1]) +
-       (int)(src[2]) +
-       256*(int)(src[3])) / 2;
-    src += 4;
-    *dest++ = (unsigned char)(i & 0xFF);
-    *dest++ = (unsigned char)((i / 256) & 0xFF); }
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit big endian signed stereo data to 16 bit big endian
-   signed mono data */
-static size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-  signed short i;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  for (count /= 2; count--; ) {
-    i = ((int)(src[1]) +
-        256*(int)(src[0]) +
-       (int)(src[3]) +
-       256*(int)(src[2])) / 2;
-    src += 4;
-    *dest++ = (unsigned char)((i / 256) & 0xFF);
-    *dest++ = (unsigned char)(i & 0xFF); }
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit little endian signed data to 8 bit unsigned data */
-static size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--) {
-    *dest++ = (unsigned char)(((signed char *)src)[1] ^ (signed char)0x80);
-    src += 2;
-  }
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit big endian signed data to 8 bit unsigned data */
-static size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 2;
-  if (count > SNDBUFSZ) { *sz  -= 2*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--) {
-    *dest++ = (unsigned char)(((signed char *)src)[0] ^ (signed char)0x80);
-    src += 2;
-  }
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit little endian signed stereo data to 8 bit unsigned
-   mono data */
-static size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 4;
-  if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--) {
-    *dest++ = (unsigned char)(((int)((signed char *)src)[1] +
-                              (int)((signed char *)src)[3]) / 2 ^ 0x80);
-    src += 4;
-  }
-  *data = src;
-  return(rc);
-}
-
-/* Convert 16 bit big endian signed stereo data to 8 bit unsigned
-   mono data */
-static size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf)
-{
-  REGISTER unsigned char *src;
-  REGISTER unsigned char *dest;
-  int rc,count;
-
-  count = *sz / 4;
-  if (count > SNDBUFSZ) { *sz  -= 4*SNDBUFSZ; count = SNDBUFSZ; }
-  else                    *sz   = 0;
-  rc      = count;
-  src     = (unsigned char *) *data;
-  *outbuf =
-  dest    = linuxplay_sndbuf;
-  while (count--) {
-    *dest++ = (unsigned char)(((int)((signed char *)src)[0] +
-                              (int)((signed char *)src)[2]) / 2 ^ 0x80);
-    src += 4;
-  }
-  *data = src;
-  return(rc);
-}
-
-/* Look at the header of the sound file and try to determine the format;
-   we can recognize files in VOC, WAVE, and, Sun/DEC-audio format--- everything
-   else is assumed to be raw 8 bit unsigned data sampled at 8kHz */
-static fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
-                             int *tracks,
-                             size_t (**parsesndfile)(void **,size_t *sz,
-                                                     void **))
-{
-  /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-  if (!memcmp(format,"Creative Voice File\x1A\x1A\x00",22) &&
-              (format[22]+256*format[23]) ==
-      ((0x1233-format[24]-256*format[25])&0xFFFF)) { /* VOC */
-    *fmt          = AFMT_U8;
-    *speed        = 8000;
-    *tracks       = 2;
-    *parsesndfile = parsevoc;
-    return(fmtVoc); }
-  else if (!memcmp(format,"RIFF",4) &&
-          !memcmp(format+8,"WAVEfmt ",8)) { /* WAVE */
-    if (memcmp(format+20,"\001\000\001"/* PCM mono */,4) &&
-       memcmp(format+20,"\001\000\002"/* PCM stereo */,4))
-      return(fmtIllegal);
-    *fmt          = (format[32]/(*tracks = format[22])) == 1 ?
-                    AFMT_U8 : AFMT_S16_LE;
-    /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-    *speed        = format[24]+256*(format[25]+256*
-                                   (format[26]+256*format[27]));
-    *parsesndfile = parsewave;
-    return(fmtWave); }
-  else if (!memcmp(format,".snd",4)) { /* Sun Audio (big endian) */
-    if (format[7]+256*(format[6]+256*(format[5]+256*format[4])) < 24) {
-      *fmt          = AFMT_MU_LAW;
-      *speed        = 8000;
-      *tracks       = 1;
-      *parsesndfile = parsesundecaudio;
-      return(fmtSunAudio); }
-    if      (!memcmp(format+12,"\000\000\000\001",4)) *fmt = AFMT_MU_LAW;
-    else if (!memcmp(format+12,"\000\000\000\002",4)) *fmt = AFMT_S8;
-    else if (!memcmp(format+12,"\000\000\000\003",4)) *fmt = AFMT_S16_BE;
-    else return(fmtIllegal);
-    /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-    *speed        = format[19]+256*(format[18]+256*
-                                   (format[17]+256*format[16]));
-    *tracks       = format[23];
-    *parsesndfile = parsesundecaudio;
-    return(fmtSunAudio); }
-  else if (!memcmp(format,".sd",4)) { /* DEC Audio (little endian) */
-    if (format[4]+256*(format[5]+256*(format[6]+256*format[7])) < 24) {
-      *fmt          = AFMT_MU_LAW;
-      *speed        = 8000;
-      *tracks       = 1;
-      *parsesndfile = parsesundecaudio;
-      return(fmtSunAudio); }
-    if      (!memcmp(format+12,"\001\000\000",4)) *fmt = AFMT_MU_LAW;
-    else if (!memcmp(format+12,"\002\000\000",4)) *fmt = AFMT_S8;
-    else if (!memcmp(format+12,"\003\000\000",4)) *fmt = AFMT_S16_LE;
-    else return(fmtIllegal);
-    /* Keep compatibility with Linux 68k, etc. by not relying on byte-sex  */
-    *speed        = format[16]+256*(format[17]+256*
-                                   (format[18]+256*format[19]));
-    *tracks       = format[20];
-    *parsesndfile = parsesundecaudio;
-    return(fmtSunAudio); }
-  else {
-    *fmt          = AFMT_U8;
-    *speed        = 8000;
-    *tracks       = 1;
-    *parsesndfile = parseraw;
-    return(fmtRaw); }
-}
-
 /* Initialize the soundcard and mixer device with the parameters that we
    found in the header of the sound file. If the soundcard is not capable of
    natively supporting the required parameters, then try to set up conversion
@@ -963,8 +278,11 @@ static int audio_init(int mixx_fd, int auddio_fd, int fmt, int speed,
 }
 
 /* XEmacs requires code both for playback of pre-loaded data and for playback
-   from a soundfile; we use one function for both cases */
-static void linux_play_data_or_file(int fd,unsigned char *data,
+   from a soundfile; we use one function for both cases.
+
+   Returns 1 on succes. 0 otherwise.
+*/
+static int linux_play_data_or_file(int fd,unsigned char *data,
                                    int length,int volume)
 {
   size_t         (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
@@ -972,17 +290,19 @@ static void linux_play_data_or_file(int fd,unsigned char *data,
   fmtType        ffmt;
   int            fmt,speed,tracks;
   unsigned char *pptr,*optr,*cptr,*sptr;
-  int            wrtn,rrtn,crtn,prtn;
+  int            wrtn, crtn;
+  size_t         prtn, rrtn;
+  unsigned char  sndbuf[SNDBUFSZ];
 
   /* We need to read at least the header information before we can start
      doing anything */
   if (!data || length < HEADERSZ) {
-    if (fd < 0) return;
+    if (fd < 0) return 0;
     else {
-      length = read(fd,linuxplay_sndbuf,SNDBUFSZ);
+      length = read(fd,sndbuf,SNDBUFSZ);
       if (length < HEADERSZ)
-       return;
-      data   = linuxplay_sndbuf;
+       return 0;
+      data   = sndbuf;
       length = SNDBUFSZ; }
   }
 
@@ -990,14 +310,16 @@ static void linux_play_data_or_file(int fd,unsigned char *data,
 
   if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
     warn("Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)");
-      return; }
+      return 0; }
 
   /* The VoxWare-SDK discourages opening /dev/audio; opening /dev/dsp and
      properly initializing it via ioctl() is preferred */
   if ((audio_fd=open(audio_dev, O_WRONLY | O_NONBLOCK, 0)) < 0) {
-    perror(audio_dev);
+    /* JV. Much too verbose. In addition this can crash. See NOTE: in
+       Fplay_sound 
+       perror(audio_dev); */
     if (mix_fd > 0 && mix_fd != audio_fd) { close(mix_fd); mix_fd = -1; }
-    return; }
+    return 0; }
 
   /* The VoxWare-SDK discourages direct manipulation of the mixer device as
      this could lead to problems, when multiple sound cards are installed */
@@ -1010,17 +332,16 @@ static void linux_play_data_or_file(int fd,unsigned char *data,
     goto END_OF_PLAY;
   audio_vol = volume;
 
-  /* Initialize global parser state information to zero */
-  memset(&parsestate,0,sizeof(parsestate));
+  reset_parsestate();
 
   /* Mainloop: read a block of data, parse its contents, perform all
                the necessary conversions and output it to the sound
                device; repeat until all data has been processed */
   rrtn = length;
   do {
-    for (pptr = data; (prtn = parsesndfile((void **)&pptr,(size_t *)&rrtn,
+    for (pptr = data; (prtn = parsesndfile((void **)&pptr, &rrtn,
                                           (void **)&optr)) > 0; )
-      for (cptr = optr; (crtn = sndcnv((void **)&cptr,(size_t *) &prtn,
+      for (cptr = optr; (crtn = sndcnv((void **)&cptr, &prtn,
                                       (void **)&sptr)) > 0; ) {
        for (;;) {
          if ((wrtn = write(audio_fd,sptr,crtn)) < 0) {
@@ -1034,17 +355,15 @@ static void linux_play_data_or_file(int fd,unsigned char *data,
          warn(buf);
          goto END_OF_PLAY; } }
     if (fd >= 0) {
-      if ((rrtn = read(fd,linuxplay_sndbuf,SNDBUFSZ)) < 0) {
+      if ((rrtn = read(fd,sndbuf,SNDBUFSZ)) < 0) {
        perror("read"); goto END_OF_PLAY; } }
     else
       break;
   } while (rrtn > 0);
 
-  /* Verify that we could fully parse the entire soundfile; this is needed
-     only for files in WAVE format */
-  if (ffmt == fmtWave && parsestate.wave.state != wvOutOfBlock &&
-      parsestate.wave.state != wvFatal)
-    warn("Unexpected end of WAVE file");
+  if (ffmt == fmtWave)
+    parse_wave_complete();
+
 
 END_OF_PLAY:
   /* Now cleanup all used resources */
@@ -1066,12 +385,11 @@ END_OF_PLAY:
   close(audio_fd);
   audio_fd = -1;
 
-  return;
+  return 1;
 }
 
 /* Call "linux_play_data_or_file" with the appropriate parameters for
    playing a soundfile */
-void play_sound_file (char *sound_file, int volume);
 void play_sound_file (char *sound_file, int volume)
 {
   int fd;
@@ -1086,9 +404,7 @@ void play_sound_file (char *sound_file, int volume)
 
 /* Call "linux_play_data_or_file" with the appropriate parameters for
    playing pre-loaded data */
-void play_sound_data (unsigned char *data, int length, int volume);
-void play_sound_data (unsigned char *data, int length, int volume)
+int play_sound_data (unsigned char *data, int length, int volume)
 {
-  linux_play_data_or_file(-1,data,length,volume);
-  return;
+  return linux_play_data_or_file(-1,data,length,volume);
 }