This commit was manufactured by cvs2svn to create branch 'XEmacs-21_4'.
authortomo <tomo>
Thu, 6 Jan 2000 06:28:00 +0000 (06:28 +0000)
committertomo <tomo>
Thu, 6 Jan 2000 06:28:00 +0000 (06:28 +0000)
lisp/gpm.el [new file with mode: 0644]
lisp/mule/auto-autoloads.el [new file with mode: 0644]
lisp/mule/custom-load.el [new file with mode: 0644]
man/internals/index.texi [new file with mode: 0644]
man/lispref/index.texi [new file with mode: 0644]
src/esd.c [new file with mode: 0644]
src/miscplay.c [new file with mode: 0644]
src/miscplay.h [new file with mode: 0644]
tests/automated/mule-tests.el [new file with mode: 0644]

diff --git a/lisp/gpm.el b/lisp/gpm.el
new file mode 100644 (file)
index 0000000..3ffd2de
--- /dev/null
@@ -0,0 +1,82 @@
+;;; gpm.el --- Support the mouse when emacs run on a Linux console.
+
+;; Copyright (C) 1999 Free Software Foundation
+
+;; Author: William Perry <wmperry@gnu.org>
+;; Keywords: mouse, terminals
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+(defvar gpm-enabled-devices (make-hash-table :test 'eq
+                                            :size 13
+                                            :weakness 'key)
+  "A hash table of devices with GPM currently turned on.")
+
+(defun gpm-mode (&optional arg device)
+  "Toggle GPM mouse mode.
+With prefix arg, turn GPM mouse mode on if and only if arg is positive."
+  (interactive (list current-prefix-arg (selected-device)))
+  (cond
+   ((null arg)                         ; Toggle
+    (if (gethash device gpm-enabled-devices)
+       (progn
+         (gpm-enable device nil)
+         (remhash device gpm-enabled-devices))
+      (gpm-enable device t)
+      (puthash device t gpm-enabled-devices)))
+   ((> arg 0)                          ; Turn on
+    (gpm-enable device t)
+    (puthash device t gpm-enabled-devices))
+   ((gethash device gpm-enabled-devices) ; Turn off
+    (gpm-enable device nil)
+    (remhash device gpm-enabled-devices))))
+
+(defun turn-on-gpm-mouse-tracking (&optional device)
+  ;; Enable mouse tracking on linux console
+  (gpm-mode 5 device))
+
+(defun turn-off-gpm-mouse-tracking (&optional device)
+  ;; Disable mouse tracking on linux console
+  (gpm-mode -5 device))
+
+(defun gpm-create-device-hook (device)
+  (if (and (not noninteractive)                ; Don't want to do this in batch mode
+          (fboundp 'gpm-enable)        ; Must have C-level GPM support
+          (eq system-type 'linux)      ; Must be running linux
+          (eq (device-type device) 'tty) ; on a tty
+          (equal "linux" (console-tty-terminal-type ; an a linux terminal type
+                          (device-console device))))
+      (turn-on-gpm-mouse-tracking device)))
+
+(defun gpm-delete-device-hook (device)
+  (if (and (not noninteractive)                ; Don't want to do this in batch mode
+          (fboundp 'gpm-enable)        ; Must have C-level GPM support
+          (eq system-type 'linux)      ; Must be running linux
+          (eq (device-type device) 'tty) ; on a tty
+          (equal "linux" (console-tty-terminal-type ; an a linux terminal type
+                          (device-console device))))
+      (turn-off-gpm-mouse-tracking device)))
+
+;; Restore normal mouse behaviour outside Emacs
+
+(add-hook 'suspend-hook 'turn-off-gpm-mouse-tracking)
+(add-hook 'suspend-resume-hook 'turn-on-gpm-mouse-tracking)
+(add-hook 'create-device-hook 'gpm-create-device-hook)
+(add-hook 'delete-device-hook 'gpm-delete-device-hook)
+
+(provide 'gpm)
diff --git a/lisp/mule/auto-autoloads.el b/lisp/mule/auto-autoloads.el
new file mode 100644 (file)
index 0000000..eaed7c8
--- /dev/null
@@ -0,0 +1,40 @@
+;;; DO NOT MODIFY THIS FILE
+(if (featurep 'mule-autoloads) (error "Already loaded"))
+\f
+;;;### (autoloads (ccl-execute-with-args check-ccl-program define-ccl-program declare-ccl-program ccl-dump ccl-compile ccl-program-p) "mule-ccl" "mule/mule-ccl.el")
+
+(autoload 'ccl-program-p "mule-ccl" "\
+T if OBJECT is a valid CCL compiled code." nil nil)
+
+(autoload 'ccl-compile "mule-ccl" "\
+Return a compiled code of CCL-PROGRAM as a vector of integer." nil nil)
+
+(autoload 'ccl-dump "mule-ccl" "\
+Disassemble compiled CCL-CODE." nil nil)
+
+(autoload 'declare-ccl-program "mule-ccl" "\
+Declare NAME as a name of CCL program.
+
+To compile a CCL program which calls another CCL program not yet
+defined, it must be declared as a CCL program in advance.
+Optional arg VECTOR is a compiled CCL code of the CCL program." nil 'macro)
+
+(autoload 'define-ccl-program "mule-ccl" "\
+Set NAME the compiled code of CCL-PROGRAM.
+CCL-PROGRAM is `eval'ed before being handed to the CCL compiler `ccl-compile'.
+The compiled code is a vector of integers." nil 'macro)
+
+(autoload 'check-ccl-program "mule-ccl" "\
+Check validity of CCL-PROGRAM.
+If CCL-PROGRAM is a symbol denoting a valid CCL program, return
+CCL-PROGRAM, else return nil.
+If CCL-PROGRAM is a vector and optional arg NAME (symbol) is supplied,
+register CCL-PROGRAM by name NAME, and return NAME." nil 'macro)
+
+(autoload 'ccl-execute-with-args "mule-ccl" "\
+Execute CCL-PROGRAM with registers initialized by the remaining args.
+The return value is a vector of resulting CCL registers." nil nil)
+
+;;;***
+
+(provide 'mule-autoloads)
diff --git a/lisp/mule/custom-load.el b/lisp/mule/custom-load.el
new file mode 100644 (file)
index 0000000..00427ba
--- /dev/null
@@ -0,0 +1,7 @@
+;;; custom-load.el --- automatically extracted custom dependencies
+
+;;; Code:
+
+(custom-add-loads 'mule '("mule-cmds"))
+
+;;; custom-load.el ends here
diff --git a/man/internals/index.texi b/man/internals/index.texi
new file mode 100644 (file)
index 0000000..4a27571
--- /dev/null
@@ -0,0 +1,37 @@
+@c -*-texinfo-*-
+@setfilename ../../info/index.info
+
+@c Indexing guidelines
+
+@c I assume that all indexes will be combined.
+@c Therefore, if a generated findex and permutations
+@c cover the ways an index user would look up the entry,
+@c then no cindex is added.
+@c Concept index (cindex) entries will also be permuted.  Therefore, they
+@c have no commas and few irrelevant connectives in them.
+
+@c I tried to include words in a cindex that give the context of the entry,
+@c particularly if there is more than one entry for the same concept.
+@c For example, "nil in keymap"
+@c Similarly for explicit findex and vindex entries, e.g. "print example".
+
+@c Error codes are given cindex entries, e.g. "end-of-file error".
+
+@c pindex is used for .el files and Unix programs
+
+@node Index,  , Interface to X Windows, Top
+@unnumbered Index
+
+@ignore
+All variables, functions, keys, programs, files, and concepts are
+in this one index.  
+
+All names and concepts are permuted, so they appear several times, one
+for each permutation of the parts of the name.  For example,
+@code{function-name} would appear as @b{function-name} and @b{name,
+function-}.  Key entries are not permuted, however.
+@end ignore
+
+@c Print the indices
+
+@printindex fn
diff --git a/man/lispref/index.texi b/man/lispref/index.texi
new file mode 100644 (file)
index 0000000..31ed313
--- /dev/null
@@ -0,0 +1,37 @@
+@c -*-texinfo-*-
+@setfilename ../../info/index.info
+
+@c Indexing guidelines
+
+@c I assume that all indexes will be combined.
+@c Therefore, if a generated findex and permutations
+@c cover the ways an index user would look up the entry,
+@c then no cindex is added.
+@c Concept index (cindex) entries will also be permuted.  Therefore, they
+@c have no commas and few irrelevant connectives in them.
+
+@c I tried to include words in a cindex that give the context of the entry,
+@c particularly if there is more than one entry for the same concept.
+@c For example, "nil in keymap"
+@c Similarly for explicit findex and vindex entries, e.g. "print example".
+
+@c Error codes are given cindex entries, e.g. "end-of-file error".
+
+@c pindex is used for .el files and Unix programs
+
+@node Index,  , Standard Hooks, Top
+@unnumbered Index
+
+@ignore
+All variables, functions, keys, programs, files, and concepts are
+in this one index.  
+
+All names and concepts are permuted, so they appear several times, one
+for each permutation of the parts of the name.  For example,
+@code{function-name} would appear as @b{function-name} and @b{name,
+function-}.  Key entries are not permuted, however.
+@end ignore
+
+@c Print the indices
+
+@printindex fn
diff --git a/src/esd.c b/src/esd.c
new file mode 100644 (file)
index 0000000..788dbbf
--- /dev/null
+++ b/src/esd.c
@@ -0,0 +1,130 @@
+/* esd.c - play a sound over ESD
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with: Not in FSF. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "lisp.h"
+#include "miscplay.h"
+
+#include <esd.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+/* the name given to ESD - I think this should identify ourselves */
+#define ESD_NAME "xemacs"
+
+int esd_play_sound_file(char *file, int vol);
+int esd_play_sound_file(char *file, int vol)
+{                              /* #### FIXME: vol is ignored */
+  return esd_play_file(ESD_NAME, file, 0);
+}
+
+int esd_play_sound_data(unsigned char *data, size_t length, int vol);
+int esd_play_sound_data(unsigned char *data, size_t length, int vol)
+{                              /* #### FIXME: vol is ignored */
+  size_t         (*parsesndfile)(void **dayta,size_t *sz,void **outbuf);
+  size_t         (*sndcnv)(void **dayta,size_t *sz,void **);
+  fmtType        ffmt;
+  int            fmt,speed,tracks;
+  unsigned char *pptr,*optr,*cptr,*sptr;
+  ssize_t        wrtn;
+  size_t         crtn;
+  size_t         prtn;
+  int flags, sock;
+
+  /* analyze_format needs at least this many bytes to work with */
+  if (length < HEADERSZ)
+    return 0;
+
+  ffmt = analyze_format(data,&fmt,&speed,&tracks,&parsesndfile);
+
+  if (ffmt != fmtRaw && ffmt != fmtSunAudio && ffmt != fmtWave) {
+    message(GETTEXT("audio: Unsupported file format (neither RAW, nor Sun/DECAudio, nor WAVE)"));
+      return 0;
+  }
+
+  /* convert header information into ESD flags */
+  flags = ESD_STREAM|ESD_PLAY;
+  sndcnv = sndcnvnop;
+  switch (fmt)
+    {
+    case AFMT_MU_LAW:
+      sndcnv = sndcnvULaw_2linear;
+      flags |= ESD_BITS8;
+      break;
+    case AFMT_S8:
+      sndcnv = sndcnv2unsigned;        /* ESD needs unsigned bytes */
+    case AFMT_U8:
+      flags |= ESD_BITS8;
+      break;
+    case AFMT_S16_BE:
+      sndcnv = sndcnv16swap;   /* ESD wants little endian */
+    case AFMT_S16_LE:
+      flags |= ESD_BITS16;
+      break;
+    default:
+      message(GETTEXT("audio: byte format %d unimplemented"), fmt);
+      return 0;
+    }
+  switch (tracks)
+    {
+    case 1: flags |= ESD_MONO; break;
+    case 2: flags |= ESD_STEREO; break;
+    default:
+      message(GETTEXT("audio: %d channels - only 1 or 2 supported"), tracks);
+      return 0;
+    }
+
+  sock = esd_play_stream(flags, speed, NULL, "xemacs");
+  if (sock < 0)
+    return 0;
+
+  reset_parsestate();
+
+  for (pptr = data; (prtn = parsesndfile((void **)&pptr,&length,
+                                        (void **)&optr)) > 0; )
+    for (cptr = optr; (crtn = sndcnv((void **)&cptr,&prtn,
+                                    (void **)&sptr)) > 0; ) {
+      if ((wrtn = write(sock,sptr,crtn)) < 0) {
+       message(GETTEXT("audio: write error (%s)"), strerror(errno));
+       goto END_OF_PLAY;
+      }
+      if (wrtn != crtn) {
+       message(GETTEXT("audio: only wrote %d of %d bytes"), wrtn, crtn);
+       goto END_OF_PLAY;
+      }
+    }
+
+  if (ffmt == fmtWave)
+    parse_wave_complete();
+
+END_OF_PLAY:
+  /* Now cleanup all used resources */
+
+  close(sock);
+  return 1;
+}
diff --git a/src/miscplay.c b/src/miscplay.c
new file mode 100644 (file)
index 0000000..37eeb17
--- /dev/null
@@ -0,0 +1,797 @@
+/* miscplay.c - general routines related to playing sounds
+ **
+ ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
+ ** This was sawed out from version 1.3 of linuxplay.c 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
+ ** information.
+ **
+ ** Permission to use, copy, modify, and distribute this software and its
+ ** documentation for any purpose and without fee is hereby granted, provided
+ ** that the above copyright notice appear in all copies and that both that
+ ** copyright notice and this permission notice appear in supporting
+ ** documentation.  This software is provided "as is" without express or
+ ** implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "miscplay.h"
+#include "lisp.h"
+#include "syssignal.h"
+#include "sysfile.h"
+#define warn(str)   message("audio: %s ",GETTEXT(str))
+
+#include <stdlib.h>
+
+#ifdef __GNUC__
+#define UNUSED(x) ((void)(x))
+#else
+#define UNUSED(x)
+#define __inline__
+#endif
+
+/* 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 miscplay_sndbuf[SNDBUFSZ];
+
+/* Initialize global parser state information to zero */
+void reset_parsestate()
+{
+  memset(&parsestate,0,sizeof(parsestate));
+}
+
+/* Verify that we could fully parse the entire soundfile; this is needed
+   only for files in WAVE format */
+int parse_wave_complete()
+{
+  if (parsestate.wave.state != wvOutOfBlock &&
+      parsestate.wave.state != wvFatal) {
+    warn("Unexpected end of WAVE file");
+    return 0;
+  } else
+    return 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 */
+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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 from 8 bit ulaw mono to 8 bit linear mono */
+size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf)
+{
+  /* conversion table stolen from Linux's ulaw.h */
+  static unsigned char ulaw_dsp[] = {
+     3,    7,   11,   15,   19,   23,   27,   31,
+    35,   39,   43,   47,   51,   55,   59,   63,
+    66,   68,   70,   72,   74,   76,   78,   80,
+    82,   84,   86,   88,   90,   92,   94,   96,
+    98,   99,  100,  101,  102,  103,  104,  105,
+   106,  107,  108,  109,  110,  111,  112,  113,
+   113,  114,  114,  115,  115,  116,  116,  117,
+   117,  118,  118,  119,  119,  120,  120,  121,
+   121,  121,  122,  122,  122,  122,  123,  123,
+   123,  123,  124,  124,  124,  124,  125,  125,
+   125,  125,  125,  125,  126,  126,  126,  126,
+   126,  126,  126,  126,  127,  127,  127,  127,
+   127,  127,  127,  127,  127,  127,  127,  127,
+   128,  128,  128,  128,  128,  128,  128,  128,
+   128,  128,  128,  128,  128,  128,  128,  128,
+   128,  128,  128,  128,  128,  128,  128,  128,
+   253,  249,  245,  241,  237,  233,  229,  225,
+   221,  217,  213,  209,  205,  201,  197,  193,
+   190,  188,  186,  184,  182,  180,  178,  176,
+   174,  172,  170,  168,  166,  164,  162,  160,
+   158,  157,  156,  155,  154,  153,  152,  151,
+   150,  149,  148,  147,  146,  145,  144,  143,
+   143,  142,  142,  141,  141,  140,  140,  139,
+   139,  138,  138,  137,  137,  136,  136,  135,
+   135,  135,  134,  134,  134,  134,  133,  133,
+   133,  133,  132,  132,  132,  132,  131,  131,
+   131,  131,  131,  131,  130,  130,  130,  130,
+   130,  130,  130,  130,  129,  129,  129,  129,
+   129,  129,  129,  129,  129,  129,  129,  129,
+   128,  128,  128,  128,  128,  128,  128,  128,
+   128,  128,  128,  128,  128,  128,  128,  128,
+   128,  128,  128,  128,  128,  128,  128,  128,
+  };
+  unsigned char *p=(unsigned char *)*data;
+
+  *outbuf = *data;
+  while ((*sz)--)
+    *p++ = ulaw_dsp[*p];
+  *sz = 0;
+  *data = p;
+  return p - (unsigned char *)*outbuf;
+}
+
+/* Convert 8 bit ulaw stereo data to 8 bit ulaw mono data */
+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    = miscplay_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);
+}
+
+size_t sndcnv16swap(void **data,size_t *sz,void **outbuf)
+{
+  /* #### Not aliasing-safe!!  Must convert to use unions instead! */
+  size_t cnt = *sz / 2;
+  unsigned short *p;
+
+  *outbuf = *data;
+  p = (unsigned short *) *outbuf;
+  while (cnt--) {
+    *p++ = ((*p & 0x00ff) << 8) | (*p >> 8);
+  }
+  *data = p;
+  cnt = *sz;
+  *sz = 0;
+  return cnt;
+}
+
+/* Convert 16 bit little endian signed stereo data to 16 bit little endian
+   signed mono data */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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    = miscplay_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 */
+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); }
+}
diff --git a/src/miscplay.h b/src/miscplay.h
new file mode 100644 (file)
index 0000000..c83030b
--- /dev/null
@@ -0,0 +1,58 @@
+/* miscplay.h - general routines related to playing sounds
+ **
+ ** Copyright (C) 1995,96 by Markus Gutschke (gutschk@math.uni-muenster.de)
+ ** This was sawed out from version 1.3 of linuxplay.c 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
+ ** information.
+ **
+ ** Permission to use, copy, modify, and distribute this software and its
+ ** documentation for any purpose and without fee is hereby granted, provided
+ ** that the above copyright notice appear in all copies and that both that
+ ** copyright notice and this permission notice appear in supporting
+ ** documentation.  This software is provided "as is" without express or
+ ** implied warranty.
+ */
+
+#include <stdlib.h>
+
+#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             */
+
+/* Audio data formats from <linux/soundcard.h> */
+#define AFMT_MU_LAW            0x00000001
+#define AFMT_A_LAW             0x00000002
+#define AFMT_IMA_ADPCM         0x00000004
+#define AFMT_U8                        0x00000008
+#define AFMT_S16_LE            0x00000010      /* Little endian signed 16*/
+#define AFMT_S16_BE            0x00000020      /* Big endian signed 16 */
+#define AFMT_S8                        0x00000040
+#define AFMT_U16_LE            0x00000080      /* Little endian U16 */
+#define AFMT_U16_BE            0x00000100      /* Big endian U16 */
+#define AFMT_MPEG              0x00000200      /* MPEG (2) audio */
+
+typedef enum {fmtIllegal,fmtRaw,fmtVoc,fmtWave,fmtSunAudio} fmtType;
+
+size_t sndcnvnop(void **data,size_t *sz,void **outbuf);
+size_t sndcnv8U_2mono(void **data,size_t *sz,void **outbuf);
+size_t sndcnv8S_2mono(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2monounsigned(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2unsigned(void **data,size_t *sz,void **outbuf);
+size_t sndcnvULaw_2linear(void **data,size_t *sz,void **outbuf);
+size_t sndcnvULaw_2mono(void **data,size_t *sz,void **outbuf);
+size_t sndcnv16swap(void **data,size_t *sz,void **outbuf);
+size_t sndcnv16_2monoLE(void **data,size_t *sz,void **outbuf);
+size_t sndcnv16_2monoBE(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2byteLE(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2byteBE(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2monobyteLE(void **data,size_t *sz,void **outbuf);
+size_t sndcnv2monobyteBE(void **data,size_t *sz,void **outbuf);
+
+fmtType analyze_format(unsigned char *format,int *fmt,int *speed,
+                             int *tracks,
+                             size_t (**parsesndfile)(void **,size_t *sz,
+                                                     void **));
+void reset_parsestate(void);
+int parse_wave_complete(void);
diff --git a/tests/automated/mule-tests.el b/tests/automated/mule-tests.el
new file mode 100644 (file)
index 0000000..729d134
--- /dev/null
@@ -0,0 +1,75 @@
+;; Copyright (C) 1999 Free Software Foundation, Inc.
+
+;; Author: Hrvoje Niksic <hniksic@xemacs.org>
+;; Maintainer: Hrvoje Niksic <hniksic@xemacs.org>
+;; Created: 1999
+;; Keywords: tests
+
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; XEmacs is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; see the file COPYING.  If not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+;; 02111-1307, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;; Test some Mule functionality (most of these remain to be written) .
+;; See test-harness.el for instructions on how to run these tests.
+
+;;-----------------------------------------------------------------
+;; Test whether all legal chars may be safely inserted to a buffer.
+;;-----------------------------------------------------------------
+
+(defun test-chars (&optional for-test-harness)
+  "Insert all characters in a buffer, to see if XEmacs will crash.
+This is done by creating a string with all the legal characters
+in [0, 2^19) range, inserting it into the buffer, and checking
+that the buffer's contents are equivalent to the string.
+
+If FOR-TEST-HARNESS is specified, a temporary buffer is used, and
+the Assert macro checks for correctness."
+  (let ((max (expt 2 (if (featurep 'mule) 19 8)))
+       (list nil)
+       (i 0))
+    (while (< i max)
+      (and (not for-test-harness)
+          (zerop (% i 1000))
+          (message "%d" i))
+      (and (int-char i)
+          ;; Don't aset to a string directly because random string
+          ;; access is O(n) under Mule.
+          (setq list (cons (int-char i) list)))
+      (setq i (1+ i)))
+    (let ((string (apply #'string (nreverse list))))
+      (if for-test-harness
+         ;; For use with test-harness, use Assert and a temporary
+         ;; buffer.
+         (with-temp-buffer
+           (insert string)
+           (Assert (equal (buffer-string) string)))
+       ;; For use without test harness: use a normal buffer, so that
+       ;; you can also test whether redisplay works.
+       (switch-to-buffer (get-buffer-create "test"))
+       (erase-buffer)
+       (buffer-disable-undo)
+       (insert string)
+       (assert (equal (buffer-string) string))))))
+
+;; It would be really *really* nice if test-harness allowed a way to
+;; run a test in byte-compiled mode only.  It's tedious to have
+;; time-consuming tests like this one run twice, once interpreted and
+;; once compiled, for no good reason.
+(test-chars t)