/* sound.c -- sound support.
- Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+
+Copyright (C) 1998-1999, 2001-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
cause an error to be generated.
The Windows implementation of play-sound is implemented via the
- Win32 API functions mciSendString, waveOutGetVolume, and
+ Windows API functions mciSendString, waveOutGetVolume, and
waveOutSetVolume which are exported by Winmm.dll.
*/
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
-#include <setjmp.h>
+
#include "lisp.h"
#include "dispextern.h"
#include "atimer.h"
-#include <signal.h>
#include "syssignal.h"
/* END: Common Includes */
/* BEGIN: Non Windows Includes */
#ifndef WINDOWSNT
-#ifndef MSDOS
#include <sys/ioctl.h>
-#endif
/* FreeBSD has machine/soundcard.h. Voxware sound driver docs mention
sys/soundcard.h. So, let's try whatever's there. */
/* BEGIN: Windows Specific Includes */
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <limits.h>
#include <windows.h>
#include <mmsystem.h>
/* Symbols. */
-extern Lisp_Object QCfile, QCdata;
-Lisp_Object QCvolume, QCdevice;
-Lisp_Object Qsound;
-Lisp_Object Qplay_sound_functions;
+static Lisp_Object QCvolume, QCdevice;
+static Lisp_Object Qsound;
+static Lisp_Object Qplay_sound_functions;
/* Indices of attributes in a sound attributes vector. */
SOUND_ATTR_SENTINEL
};
-static void alsa_sound_perror P_ ((char *, int)) NO_RETURN;
-static void sound_perror P_ ((char *)) NO_RETURN;
-static void sound_warning P_ ((char *));
-static int parse_sound P_ ((Lisp_Object, Lisp_Object *));
-
/* END: Common Definitions */
/* BEGIN: Non Windows Definitions */
#ifndef WINDOWSNT
-#ifndef DEFAULT_SOUND_DEVICE
-#define DEFAULT_SOUND_DEVICE "/dev/dsp"
-#endif
-#ifndef DEFAULT_ALSA_SOUND_DEVICE
-#define DEFAULT_ALSA_SOUND_DEVICE "default"
-#endif
-
-
/* Structure forward declarations. */
struct sound;
int channels;
/* Open device SD. */
- void (* open) P_ ((struct sound_device *sd));
+ void (* open) (struct sound_device *sd);
/* Close device SD. */
- void (* close) P_ ((struct sound_device *sd));
+ void (* close) (struct sound_device *sd);
- /* Configure SD accoring to device-dependent parameters. */
- void (* configure) P_ ((struct sound_device *device));
+ /* Configure SD according to device-dependent parameters. */
+ void (* configure) (struct sound_device *device);
/* Choose a device-dependent format for outputting sound S. */
- void (* choose_format) P_ ((struct sound_device *sd,
- struct sound *s));
+ void (* choose_format) (struct sound_device *sd,
+ struct sound *s);
/* Return a preferred data size in bytes to be sent to write (below)
each time. 2048 is used if this is NULL. */
- int (* period_size) P_ ((struct sound_device *sd));
+ ptrdiff_t (* period_size) (struct sound_device *sd);
/* Write NYBTES bytes from BUFFER to device SD. */
- void (* write) P_ ((struct sound_device *sd, const char *buffer,
- int nbytes));
+ void (* write) (struct sound_device *sd, const char *buffer,
+ ptrdiff_t nbytes);
/* A place for devices to store additional data. */
void *data;
read from the start of a sound file. */
char *header;
- /* Number of bytes raed from sound file. This is always <=
+ /* Number of bytes read from sound file. This is always <=
MAX_SOUND_HEADER_BYTES. */
int header_size;
Lisp_Object data;
/* Play sound file S on device SD. */
- void (* play) P_ ((struct sound *s, struct sound_device *sd));
+ void (* play) (struct sound *s, struct sound_device *sd);
};
/* These are set during `play-sound-internal' so that sound_cleanup has
access to them. */
-struct sound_device *current_sound_device;
-struct sound *current_sound;
+static struct sound_device *current_sound_device;
+static struct sound *current_sound;
/* Function prototypes. */
-static void vox_open P_ ((struct sound_device *));
-static void vox_configure P_ ((struct sound_device *));
-static void vox_close P_ ((struct sound_device *sd));
-static void vox_choose_format P_ ((struct sound_device *, struct sound *));
-static int vox_init P_ ((struct sound_device *));
-static void vox_write P_ ((struct sound_device *, const char *, int));
-static void find_sound_type P_ ((struct sound *));
-static u_int32_t le2hl P_ ((u_int32_t));
-static u_int16_t le2hs P_ ((u_int16_t));
-static u_int32_t be2hl P_ ((u_int32_t));
-static int wav_init P_ ((struct sound *));
-static void wav_play P_ ((struct sound *, struct sound_device *));
-static int au_init P_ ((struct sound *));
-static void au_play P_ ((struct sound *, struct sound_device *));
+static void vox_open (struct sound_device *);
+static void vox_configure (struct sound_device *);
+static void vox_close (struct sound_device *sd);
+static void vox_choose_format (struct sound_device *, struct sound *);
+static int vox_init (struct sound_device *);
+static void vox_write (struct sound_device *, const char *, ptrdiff_t);
+static void find_sound_type (struct sound *);
+static u_int32_t le2hl (u_int32_t);
+static u_int16_t le2hs (u_int16_t);
+static u_int32_t be2hl (u_int32_t);
+static int wav_init (struct sound *);
+static void wav_play (struct sound *, struct sound_device *);
+static int au_init (struct sound *);
+static void au_play (struct sound *, struct sound_device *);
#if 0 /* Currently not used. */
-static u_int16_t be2hs P_ ((u_int16_t));
+static u_int16_t be2hs (u_int16_t);
#endif
/* END: Non Windows Definitions */
#else /* WINDOWSNT */
/* BEGIN: Windows Specific Definitions */
-static int do_play_sound P_ ((const char *, unsigned long));
+static int do_play_sound (const char *, unsigned long);
/*
END: Windows Specific Definitions */
#endif /* WINDOWSNT */
/* Like perror, but signals an error. */
-static void
-sound_perror (msg)
- char *msg;
+static _Noreturn void
+sound_perror (const char *msg)
{
int saved_errno = errno;
turn_on_atimers (1);
-#ifdef SIGIO
- sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ {
+ sigset_t unblocked;
+ sigemptyset (&unblocked);
+ sigaddset (&unblocked, SIGIO);
+ pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
+ }
#endif
if (saved_errno != 0)
error ("%s: %s", msg, strerror (saved_errno));
/* Display a warning message. */
static void
-sound_warning (msg)
- char *msg;
+sound_warning (const char *msg)
{
- message (msg);
+ message ("%s", msg);
}
range [0, 1]. */
static int
-parse_sound (sound, attrs)
- Lisp_Object sound;
- Lisp_Object *attrs;
+parse_sound (Lisp_Object sound, Lisp_Object *attrs)
{
/* SOUND must be a list starting with the symbol `sound'. */
if (!CONSP (sound) || !EQ (XCAR (sound), Qsound))
S is the sound file structure to fill in. */
static void
-find_sound_type (s)
- struct sound *s;
+find_sound_type (struct sound *s)
{
if (!wav_init (s) && !au_init (s))
error ("Unknown sound format");
/* Function installed by play-sound-internal with record_unwind_protect. */
static Lisp_Object
-sound_cleanup (arg)
- Lisp_Object arg;
+sound_cleanup (Lisp_Object arg)
{
if (current_sound_device->close)
current_sound_device->close (current_sound_device);
if (current_sound->fd > 0)
emacs_close (current_sound->fd);
- free (current_sound_device);
- free (current_sound);
+ xfree (current_sound_device);
+ xfree (current_sound);
return Qnil;
}
to host byte-order. */
static u_int32_t
-le2hl (value)
- u_int32_t value;
+le2hl (u_int32_t value)
{
-#ifdef WORDS_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
unsigned char *p = (unsigned char *) &value;
value = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
#endif
to host byte-order. */
static u_int16_t
-le2hs (value)
- u_int16_t value;
+le2hs (u_int16_t value)
{
-#ifdef WORDS_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
unsigned char *p = (unsigned char *) &value;
value = p[0] + (p[1] << 8);
#endif
to host byte-order. */
static u_int32_t
-be2hl (value)
- u_int32_t value;
+be2hl (u_int32_t value)
{
-#ifndef WORDS_BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
unsigned char *p = (unsigned char *) &value;
value = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24);
#endif
to host byte-order. */
static u_int16_t
-be2hs (value)
- u_int16_t value;
+be2hs (u_int16_t value)
{
-#ifndef WORDS_BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
unsigned char *p = (unsigned char *) &value;
value = p[1] + (p[0] << 8);
#endif
Value is non-zero if the file is a WAV file. */
static int
-wav_init (s)
- struct sound *s;
+wav_init (struct sound *s)
{
struct wav_header *header = (struct wav_header *) s->header;
if (s->header_size < sizeof *header
- || bcmp (s->header, "RIFF", 4) != 0)
+ || memcmp (s->header, "RIFF", 4) != 0)
return 0;
/* WAV files are in little-endian order. Convert the header
/* Play RIFF-WAVE audio file S on sound device SD. */
static void
-wav_play (s, sd)
- struct sound *s;
- struct sound_device *sd;
+wav_play (struct sound *s, struct sound_device *sd)
{
struct wav_header *header = (struct wav_header *) s->header;
files I found so far. If someone feels inclined to implement the
whole RIFF-WAVE spec, please do. */
if (STRINGP (s->data))
- sd->write (sd, SDATA (s->data) + sizeof *header,
+ sd->write (sd, SSDATA (s->data) + sizeof *header,
SBYTES (s->data) - sizeof *header);
else
{
char *buffer;
- int nbytes;
- int blksize = sd->period_size ? sd->period_size (sd) : 2048;
- int data_left = header->data_length;
+ ptrdiff_t nbytes = 0;
+ ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
+ ptrdiff_t data_left = header->data_length;
- buffer = (char *) alloca (blksize);
+ buffer = alloca (blksize);
lseek (s->fd, sizeof *header, SEEK_SET);
while (data_left > 0
&& (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
Value is non-zero if the file is an AU file. */
static int
-au_init (s)
- struct sound *s;
+au_init (struct sound *s)
{
struct au_header *header = (struct au_header *) s->header;
if (s->header_size < sizeof *header
- || bcmp (s->header, ".snd", 4) != 0)
+ || memcmp (s->header, ".snd", 4) != 0)
return 0;
header->magic_number = be2hl (header->magic_number);
/* Play Sun audio file S on sound device SD. */
static void
-au_play (s, sd)
- struct sound *s;
- struct sound_device *sd;
+au_play (struct sound *s, struct sound_device *sd)
{
struct au_header *header = (struct au_header *) s->header;
sd->configure (sd);
if (STRINGP (s->data))
- sd->write (sd, SDATA (s->data) + header->data_offset,
+ sd->write (sd, SSDATA (s->data) + header->data_offset,
SBYTES (s->data) - header->data_offset);
else
{
- int blksize = sd->period_size ? sd->period_size (sd) : 2048;
+ ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
char *buffer;
- int nbytes;
+ ptrdiff_t nbytes;
/* Seek */
lseek (s->fd, header->data_offset, SEEK_SET);
/* Copy sound data to the device. */
- buffer = (char *) alloca (blksize);
+ buffer = alloca (blksize);
while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
sd->write (sd, buffer, nbytes);
otherwise use a default device name. */
static void
-vox_open (sd)
- struct sound_device *sd;
+vox_open (struct sound_device *sd)
{
- char *file;
+ const char *file;
- /* Open the sound device. Default is /dev/dsp. */
+ /* Open the sound device (eg /dev/dsp). */
if (sd->file)
file = sd->file;
else
/* Configure device SD from parameters in it. */
static void
-vox_configure (sd)
- struct sound_device *sd;
+vox_configure (struct sound_device *sd)
{
int val;
+#ifdef USABLE_SIGIO
+ sigset_t blocked;
+#endif
- xassert (sd->fd >= 0);
+ eassert (sd->fd >= 0);
/* On GNU/Linux, it seems that the device driver doesn't like to be
interrupted by a signal. Block the ones we know to cause
troubles. */
turn_on_atimers (0);
-#ifdef SIGIO
- sigblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGIO);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
#endif
val = sd->format;
}
turn_on_atimers (1);
-#ifdef SIGIO
- sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
#endif
}
/* Close device SD if it is open. */
static void
-vox_close (sd)
- struct sound_device *sd;
+vox_close (struct sound_device *sd)
{
if (sd->fd >= 0)
{
/* On GNU/Linux, it seems that the device driver doesn't like to
be interrupted by a signal. Block the ones we know to cause
troubles. */
-#ifdef SIGIO
- sigblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ sigset_t blocked;
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGIO);
+ pthread_sigmask (SIG_BLOCK, &blocked, 0);
#endif
turn_on_atimers (0);
ioctl (sd->fd, SNDCTL_DSP_SYNC, NULL);
turn_on_atimers (1);
-#ifdef SIGIO
- sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ pthread_sigmask (SIG_UNBLOCK, &blocked, 0);
#endif
/* Close the device. */
/* Choose device-dependent format for device SD from sound file S. */
static void
-vox_choose_format (sd, s)
- struct sound_device *sd;
- struct sound *s;
+vox_choose_format (struct sound_device *sd, struct sound *s)
{
if (s->type == RIFF)
{
}
}
else
- abort ();
+ emacs_abort ();
}
structure. */
static int
-vox_init (sd)
- struct sound_device *sd;
+vox_init (struct sound_device *sd)
{
- char *file;
+ const char *file;
int fd;
- /* Open the sound device. Default is /dev/dsp. */
+ /* Open the sound device (eg /dev/dsp). */
if (sd->file)
file = sd->file;
else
/* Write NBYTES bytes from BUFFER to device SD. */
static void
-vox_write (sd, buffer, nbytes)
- struct sound_device *sd;
- const char *buffer;
- int nbytes;
+vox_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
{
- int nwritten = emacs_write (sd->fd, buffer, nbytes);
- if (nwritten < 0)
+ if (emacs_write (sd->fd, buffer, nbytes) != nbytes)
sound_perror ("Error writing to sound device");
}
/* This driver is available on GNU/Linux. */
-static void
-alsa_sound_perror (msg, err)
- char *msg;
- int err;
+#ifndef DEFAULT_ALSA_SOUND_DEVICE
+#define DEFAULT_ALSA_SOUND_DEVICE "default"
+#endif
+
+static _Noreturn void
+alsa_sound_perror (const char *msg, int err)
{
error ("%s: %s", msg, snd_strerror (err));
}
otherwise use a default device name. */
static void
-alsa_open (sd)
- struct sound_device *sd;
+alsa_open (struct sound_device *sd)
{
- char *file;
+ const char *file;
struct alsa_params *p;
int err;
else
file = DEFAULT_ALSA_SOUND_DEVICE;
- p = xmalloc (sizeof (*p));
+ p = xmalloc (sizeof *p);
p->handle = NULL;
p->hwparams = NULL;
p->swparams = NULL;
alsa_sound_perror (file, err);
}
-static int
-alsa_period_size (sd)
- struct sound_device *sd;
+static ptrdiff_t
+alsa_period_size (struct sound_device *sd)
{
struct alsa_params *p = (struct alsa_params *) sd->data;
int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
}
static void
-alsa_configure (sd)
- struct sound_device *sd;
+alsa_configure (struct sound_device *sd)
{
int val, err, dir;
unsigned uval;
struct alsa_params *p = (struct alsa_params *) sd->data;
snd_pcm_uframes_t buffer_size;
- xassert (p->handle != 0);
+ eassert (p->handle != 0);
err = snd_pcm_hw_params_malloc (&p->hwparams);
if (err < 0)
err = snd_pcm_hw_params_get_buffer_size (p->hwparams, &buffer_size);
if (err < 0)
- alsa_sound_perror("Unable to get buffer size for playback", err);
+ alsa_sound_perror ("Unable to get buffer size for playback", err);
err = snd_pcm_sw_params_current (p->handle, p->swparams);
if (err < 0)
int chn;
snd_mixer_t *handle;
snd_mixer_elem_t *e;
- char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
+ const char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
if (snd_mixer_open (&handle, 0) >= 0)
{
snd_mixer_selem_set_playback_volume (e, chn, vol);
}
}
- snd_mixer_close(handle);
+ snd_mixer_close (handle);
}
}
}
/* Close device SD if it is open. */
static void
-alsa_close (sd)
- struct sound_device *sd;
+alsa_close (struct sound_device *sd)
{
struct alsa_params *p = (struct alsa_params *) sd->data;
if (p)
snd_pcm_drain (p->handle);
snd_pcm_close (p->handle);
}
- free (p);
+ xfree (p);
}
}
/* Choose device-dependent format for device SD from sound file S. */
static void
-alsa_choose_format (sd, s)
- struct sound_device *sd;
- struct sound *s;
+alsa_choose_format (struct sound_device *sd, struct sound *s)
{
- struct alsa_params *p = (struct alsa_params *) sd->data;
if (s->type == RIFF)
{
struct wav_header *h = (struct wav_header *) s->header;
}
}
else
- abort ();
+ emacs_abort ();
}
/* Write NBYTES bytes from BUFFER to device SD. */
static void
-alsa_write (sd, buffer, nbytes)
- struct sound_device *sd;
- const char *buffer;
- int nbytes;
+alsa_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
{
struct alsa_params *p = (struct alsa_params *) sd->data;
/* The the third parameter to snd_pcm_writei is frames, not bytes. */
int fact = snd_pcm_format_size (sd->format, 1) * sd->channels;
- int nwritten = 0;
+ ptrdiff_t nwritten = 0;
int err;
while (nwritten < nbytes)
else if (err == -ESTRPIPE)
{
while ((err = snd_pcm_resume (p->handle)) == -EAGAIN)
- sleep(1); /* wait until the suspend flag is released */
+ sleep (1); /* wait until the suspend flag is released */
if (err < 0)
{
err = snd_pcm_prepare (p->handle);
}
static void
-snd_error_quiet (file, line, function, err, fmt)
- const char *file;
- int line;
- const char *function;
- int err;
- const char *fmt;
+snd_error_quiet (const char *file, int line, const char *function, int err,
+ const char *fmt)
{
}
structure. */
static int
-alsa_init (sd)
- struct sound_device *sd;
+alsa_init (struct sound_device *sd)
{
- char *file;
+ const char *file;
snd_pcm_t *handle;
int err;
}
static int
-do_play_sound (psz_file, ui_volume)
- const char *psz_file;
- unsigned long ui_volume;
+do_play_sound (const char *psz_file, unsigned long ui_volume)
{
int i_result = 0;
MCIERROR mci_error = 0;
doc: /* Play sound SOUND.
Internal use only, use `play-sound' instead. */)
- (sound)
- Lisp_Object sound;
+ (Lisp_Object sound)
{
Lisp_Object attrs[SOUND_ATTR_SENTINEL];
- int count = SPECPDL_INDEX ();
+ ptrdiff_t count = SPECPDL_INDEX ();
#ifndef WINDOWSNT
Lisp_Object file;
#ifndef WINDOWSNT
file = Qnil;
GCPRO2 (sound, file);
- current_sound_device = (struct sound_device *) xmalloc (sizeof (struct sound_device));
- bzero (current_sound_device, sizeof (struct sound_device));
- current_sound = (struct sound *) xmalloc (sizeof (struct sound));
- bzero (current_sound, sizeof (struct sound));
+ current_sound_device = xzalloc (sizeof *current_sound_device);
+ current_sound = xzalloc (sizeof *current_sound);
record_unwind_protect (sound_cleanup, Qnil);
- current_sound->header = (char *) alloca (MAX_SOUND_HEADER_BYTES);
+ current_sound->header = alloca (MAX_SOUND_HEADER_BYTES);
if (STRINGP (attrs[SOUND_FILE]))
{
{
current_sound->data = attrs[SOUND_DATA];
current_sound->header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (current_sound->data));
- bcopy (SDATA (current_sound->data), current_sound->header, current_sound->header_size);
+ memcpy (current_sound->header, SDATA (current_sound->data),
+ current_sound->header_size);
}
/* Find out the type of sound. Give up if we can't tell. */
if (STRINGP (attrs[SOUND_DEVICE]))
{
int len = SCHARS (attrs[SOUND_DEVICE]);
- current_sound_device->file = (char *) alloca (len + 1);
- strcpy (current_sound_device->file, SDATA (attrs[SOUND_DEVICE]));
+ current_sound_device->file = alloca (len + 1);
+ strcpy (current_sound_device->file, SSDATA (attrs[SOUND_DEVICE]));
}
if (INTEGERP (attrs[SOUND_VOLUME]))
lo_file = Fexpand_file_name (attrs[SOUND_FILE], Qnil);
len = XSTRING (lo_file)->size;
- psz_file = (char *) alloca (len + 1);
+ psz_file = alloca (len + 1);
strcpy (psz_file, XSTRING (lo_file)->data);
if (INTEGERP (attrs[SOUND_VOLUME]))
{
}
else if (FLOATP (attrs[SOUND_VOLUME]))
{
- ui_volume_tmp = (unsigned long) XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
+ ui_volume_tmp = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
}
/*
Based on some experiments I have conducted, a value of 100 or less
***********************************************************************/
void
-syms_of_sound ()
+syms_of_sound (void)
{
- QCdevice = intern_c_string(":device");
- staticpro (&QCdevice);
- QCvolume = intern_c_string (":volume");
- staticpro (&QCvolume);
- Qsound = intern_c_string ("sound");
- staticpro (&Qsound);
- Qplay_sound_functions = intern_c_string ("play-sound-functions");
- staticpro (&Qplay_sound_functions);
+ DEFSYM (QCdevice, ":device");
+ DEFSYM (QCvolume, ":volume");
+ DEFSYM (Qsound, "sound");
+ DEFSYM (Qplay_sound_functions, "play-sound-functions");
defsubr (&Splay_sound_internal);
}
-
-void
-init_sound ()
-{
-}
-
#endif /* HAVE_SOUND */
-
-/* arch-tag: dd850ad8-0433-4e2c-9cba-b7aeeccc0dbd
- (do not change this comment) */