* correct error facilities.
* 4/11/94, rjc Added wait_for_sounds to be called when user wants to
* be sure all play has finished.
+ * 1998-10-01 rlt Added support for WAVE files.
*/
#ifdef emacs
#include <config.h>
#include "lisp.h"
+#include "sysdep.h"
+#include "syssignal.h"
#endif
-#if __STDC__ || defined (STDC_HEADERS)
-# include <stdlib.h>
-# include <stdarg.h>
-# include <string.h>
-#endif
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include <stdio.h>
-#include "syssignal.h"
#undef LITTLE_ENDIAN
#undef BIG_ENDIAN
#include <audio/audiolib.h>
#include <audio/soundlib.h>
#include <audio/snd.h>
+#include <audio/wave.h>
#include <audio/fileutil.h>
#ifdef emacs
#else /* !emacs */
# define warn(str) fprintf (stderr, "%s\n", (str))
-# define CONST const
#endif /* emacs */
#ifdef XTOOLKIT
#else
char *server
#endif
+ );
+char *
+init_play (
+#ifdef XTOOLKIT
+ Display *display
+#else
+ char *server
+#endif
)
{
char *err_message;
- SIGTYPE (*old_sigpipe) ();
+ SIGTYPE (*old_sigpipe) (int);
#ifdef XTOOLKIT
char * server = DisplayString (display);
return NULL;
}
-void
+static void
close_down_play (void)
{
\********************************************************************/
static void
-doneCB (AuServer *aud,
+doneCB (AuServer *auserver,
AuEventHandlerRec *handler,
AuEvent *ev,
AuPointer data)
if (list == NULL)
{
- unsigned char *my_buf;
+ AuPointer my_buf;
if (buf==NULL)
{
- if ((my_buf=malloc (SoundNumBytes (s)))==NULL)
+ if ((my_buf= (AuPointer) malloc (SoundNumBytes (s)))==NULL)
{
return;
}
- if (SoundReadFile (my_buf, SoundNumBytes (s), s) != SoundNumBytes (s))
+ if (SoundReadFile ((char *) my_buf, SoundNumBytes (s), s) != SoundNumBytes (s))
{
free (my_buf);
return;
}
}
else
- my_buf=buf;
+ my_buf = (AuPointer) buf;
id = AuSoundCreateBucketFromData (aud,
s,
#endif /* CACHE_SOUNDS */
+void wait_for_sounds (void);
void
wait_for_sounds (void)
}
}
+int play_sound_file (char *sound_file, int volume);
int
play_sound_file (char *sound_file,
int volume)
{
- SIGTYPE (*old_sigpipe) ();
+ SIGTYPE (*old_sigpipe) (int);
#ifdef ROBUST_PLAY
old_sigpipe=signal (SIGPIPE, sigpipe_handle);
return 1;
}
+int play_sound_data (unsigned char *data, int length, int volume);
int
play_sound_data (unsigned char *data,
int length,
{
Sound s;
int offset;
- SIGTYPE (*old_sigpipe) ();
+ SIGTYPE (*old_sigpipe) (int);
#if !defined (XTEVENTS)
AuEvent ev;
/* hack, hack */
offset = ((SndInfo *) (s->formatInfo))->h.dataOffset;
}
+ else if (SoundFileFormat (s) == SoundFileFormatWave)
+ {
+ offset = ((WaveInfo *) (s->formatInfo))->dataOffset;
+ }
else
{
- warn ("only understand snd files at the moment");
+ warn ("only understand snd and wave files at the moment");
SoundCloseFile (s);
#ifdef ROBUST_PLAY
signal (SIGPIPE, old_sigpipe);
longjmp (AuXtErrorJump, 1);
#endif /* XTEVENTS */
+ return 0;
}
SIGTYPE
/* Create a name from the sound. */
static char *
-NameFromData (CONST unsigned char *buf,
+NameFromData (const char *buf,
int len)
{
- unsigned char name[9];
+ char name[9];
int i;
char *s;
if (i==8)
{
- strcpy (s=malloc (10), name);
+ strcpy (s = (char *) malloc (10), name);
}
else
{
- strcpy (s=malloc (15), "short sound");
+ strcpy (s = (char *) malloc (15), "short sound");
}
return s;
*/
static SndInfo *
-SndOpenDataForReading (CONST char *data,
+SndOpenDataForReading (const char *data,
int length)
{
return si;
}
+/* Stuff taken from wave.c from NAS. Just like snd files, NAS can't
+ read wave data from memory, so these functions do that for us. */
+
+#define Err() { return NULL; }
+#define readFourcc(_f) dread(_f, sizeof(RIFF_FOURCC), 1)
+#define cmpID(_x, _y) \
+ strncmp((char *) (_x), (char *) (_y), sizeof(RIFF_FOURCC))
+#define PAD2(_x) (((_x) + 1) & ~1)
+
+/* These functions here are for faking file I/O from buffer. */
+
+/* The "file" position */
+static size_t file_posn;
+/* The length of the "file" */
+static size_t file_len;
+/* The actual "file" data. */
+static const void* file_data;
+
+/* Like fopen, but for a buffer in memory */
+static void
+dopen (const void* data, size_t length)
+{
+ file_data = data;
+ file_len = length;
+ file_posn = 0;
+}
+
+/* Like fread, but for a buffer in memory */
+static int
+dread (void* buf, size_t size, size_t nitems)
+{
+ size_t nread = size * nitems;
+
+ if (file_posn + nread <= file_len)
+ {
+ memcpy(buf, (char *) file_data + file_posn, size * nitems);
+ file_posn += nread;
+ return nitems;
+ }
+ else
+ {
+ return EOF;
+ }
+}
+
+/* Like fgetc, but for a buffer in memory */
+static int
+dgetc (void)
+{
+ if (file_posn < file_len)
+ return ((char *)file_data)[file_posn++];
+ else
+ return -1;
+}
+
+/* Like fseek, but for a buffer in memory */
+static int
+dseek (long offset, int from)
+{
+ if (from == 0)
+ file_posn = offset;
+ else if (from == 1)
+ file_posn += offset;
+ else if (from == 2)
+ file_posn = file_len + offset;
+
+ return 0;
+}
+
+/* Like ftell, but for a buffer in memory */
+static long
+dtell (void)
+{
+ return file_posn;
+}
+
+/* Data buffer analogs for FileReadS and FileReadL in NAS. */
+
+static unsigned short
+DataReadS (int swapit)
+{
+ unsigned short us;
+
+ dread(&us, 2, 1);
+ if (swapit)
+ us = FileSwapS(us);
+ return us;
+}
+
+static AuUint32
+DataReadL (int swapit)
+{
+ AuUint32 ul;
+
+ dread(&ul, 4, 1);
+ if (swapit)
+ ul = FileSwapL(ul);
+ return ul;
+}
+
+static int
+readChunk (RiffChunk *c)
+{
+ int status;
+ char n;
+
+ if ((status = dread(c, sizeof(RiffChunk), 1)))
+ if (BIG_ENDIAN)
+ swapl(&c->ckSize, n);
+
+ return status;
+}
+
+/* A very straight-forward translation of WaveOpenFileForReading to
+ read the wave data from a buffer in memory. */
+
+static WaveInfo *
+WaveOpenDataForReading (const char *data,
+ int length)
+{
+ RiffChunk ck;
+ RIFF_FOURCC fourcc;
+ AuInt32 fileSize;
+ WaveInfo *wi;
+
+
+ if (!(wi = (WaveInfo *) malloc(sizeof(WaveInfo))))
+ return NULL;
+
+ wi->comment = NULL;
+ wi->dataOffset = wi->format = wi->writing = 0;
+
+ dopen(data, length);
+
+ if (!readChunk(&ck) ||
+ cmpID(&ck.ckID, RIFF_RiffID) ||
+ !readFourcc(&fourcc) ||
+ cmpID(&fourcc, RIFF_WaveID))
+ Err();
+
+ fileSize = PAD2(ck.ckSize) - sizeof(RIFF_FOURCC);
+
+ while (fileSize >= sizeof(RiffChunk))
+ {
+ if (!readChunk(&ck))
+ Err();
+
+ fileSize -= sizeof(RiffChunk) + PAD2(ck.ckSize);
+
+ /* LIST chunk */
+ if (!cmpID(&ck.ckID, RIFF_ListID))
+ {
+ if (!readFourcc(&fourcc))
+ Err();
+
+ /* INFO chunk */
+ if (!cmpID(&fourcc, RIFF_ListInfoID))
+ {
+ ck.ckSize -= sizeof(RIFF_FOURCC);
+
+ while (ck.ckSize)
+ {
+ RiffChunk c;
+
+ if (!readChunk(&c))
+ Err();
+
+ /* ICMT chunk */
+ if (!cmpID(&c.ckID, RIFF_InfoIcmtID))
+ {
+ if (!(wi->comment = (char *) malloc(c.ckSize)) ||
+ !dread(wi->comment, c.ckSize, 1))
+ Err();
+
+ if (c.ckSize & 1)
+ dgetc(); /* eat the pad byte */
+ }
+ else
+ /* skip unknown chunk */
+ dseek(PAD2(c.ckSize), 1);
+
+ ck.ckSize -= sizeof(RiffChunk) + PAD2(c.ckSize);
+ }
+ }
+ else
+ /* skip unknown chunk */
+ dseek(PAD2(ck.ckSize) - sizeof(RIFF_FOURCC), 1);
+ }
+ /* wave format chunk */
+ else if (!cmpID(&ck.ckID, RIFF_WaveFmtID) && !wi->format)
+ {
+ AuInt32 dummy;
+
+ wi->format = DataReadS(BIG_ENDIAN);
+ wi->channels = DataReadS(BIG_ENDIAN);
+ wi->sampleRate = DataReadL(BIG_ENDIAN);
+
+ /* we don't care about the next two fields */
+ dummy = DataReadL(BIG_ENDIAN);
+ dummy = DataReadS(BIG_ENDIAN);
+
+ if (wi->format != RIFF_WAVE_FORMAT_PCM)
+ Err();
+
+ wi->bitsPerSample = DataReadS(BIG_ENDIAN);
+
+ /* skip any other format specific fields */
+ dseek(PAD2(ck.ckSize - 16), 1);
+ }
+ /* wave data chunk */
+ else if (!cmpID(&ck.ckID, RIFF_WaveDataID) && !wi->dataOffset)
+ {
+ long endOfFile;
+
+ wi->dataOffset = dtell();
+ wi->dataSize = ck.ckSize;
+ dseek(0, 2);
+ endOfFile = dtell();
+
+ /* seek past the data */
+ if (dseek(wi->dataOffset + PAD2(ck.ckSize), 0) ||
+ dtell() > endOfFile)
+ {
+ /* the seek failed, assume the size is bogus */
+ dseek(0, 2);
+ wi->dataSize = dtell() - wi->dataOffset;
+ }
+
+ wi->dataOffset -= sizeof(long);
+ }
+ else
+ /* skip unknown chunk */
+ dseek(PAD2(ck.ckSize), 1);
+ }
+
+ if (!wi->dataOffset)
+ Err();
+
+ wi->numSamples = wi->dataSize / wi->channels / (wi->bitsPerSample >> 3);
+
+ if (!wi->comment)
+ wi->comment = NameFromData (data + wi->dataOffset,
+ length - wi->dataOffset);
+
+ wi->fp = NULL;
+
+ return wi;
+}
+
+
static Sound
SoundOpenDataForReading (unsigned char *data,
int length)
if (!(s = (Sound) malloc (sizeof (SoundRec))))
return NULL;
- if ((s->formatInfo = SndOpenDataForReading (data, length))==NULL)
+ if ((s->formatInfo = SndOpenDataForReading ((char *) data, length)) != NULL)
{
- free (s);
- return NULL;
+ if (!((int(*)(Sound))(SoundFileInfo[SoundFileFormatSnd].toSound)) (s))
+ {
+ SndCloseFile ((SndInfo *) (s->formatInfo));
+ free (s);
+ return NULL;
+ }
}
-
-
- if (!(SoundFileInfo[SoundFileFormatSnd].toSound) (s))
+ else if ((s->formatInfo = WaveOpenDataForReading ((char *) data, length)) != NULL)
{
- SndCloseFile (s->formatInfo);
- free (s);
- return NULL;
+ if (!((int(*)(Sound))(SoundFileInfo[SoundFileFormatWave].toSound)) (s))
+ {
+ WaveCloseFile ((WaveInfo *) (s->formatInfo));
+ free (s);
+ return NULL;
+ }
}
return s;
}
-