/* sound.c -- sound support.
- Copyright (C) 1998-1999, 2001-2012 Free Software Foundation, Inc.
+
+Copyright (C) 1998-1999, 2001-2015 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
+#include <byteswap.h>
+
#include <sys/ioctl.h>
/* FreeBSD has machine/soundcard.h. Voxware sound driver docs mention
/* BEGIN: Windows Specific Includes */
#include <stdio.h>
#include <limits.h>
+#include <mbstring.h>
#include <windows.h>
#include <mmsystem.h>
+
+#include "coding.h"
+#include "w32common.h"
+#include "w32.h"
/* END: Windows Specific Includes */
#endif /* WINDOWSNT */
SOUND_ATTR_SENTINEL
};
-#ifdef HAVE_ALSA
-static void alsa_sound_perror (const char *, int) NO_RETURN;
-#endif
-static void sound_perror (const char *) NO_RETURN;
-static void sound_warning (const char *);
-static int parse_sound (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;
struct sound_device
{
- /* The name of the device or null meaning use a default device name. */
- char *file;
+ /* If a string, the name of the device; otherwise use a default. */
+ Lisp_Object file;
/* File descriptor of the device. */
int fd;
/* Return a preferred data size in bytes to be sent to write (below)
each time. 2048 is used if this is NULL. */
- EMACS_INT (* period_size) (struct sound_device *sd);
+ ptrdiff_t (* period_size) (struct sound_device *sd);
/* Write NYBTES bytes from BUFFER to device SD. */
void (* write) (struct sound_device *sd, const char *buffer,
- EMACS_INT nbytes);
+ ptrdiff_t nbytes);
/* A place for devices to store additional data. */
void *data;
/* Function prototypes. */
-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 *, EMACS_INT);
-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 vox_write (struct sound_device *, const char *, ptrdiff_t);
+static bool wav_init (struct sound *);
static void wav_play (struct sound *, struct sound_device *);
-static int au_init (struct sound *);
+static bool au_init (struct sound *);
static void au_play (struct sound *, struct sound_device *);
-#if 0 /* Currently not used. */
-static u_int16_t be2hs (u_int16_t);
-#endif
-
/* END: Non Windows Definitions */
#else /* WINDOWSNT */
/* Like perror, but signals an error. */
-static void
+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));
static void
sound_warning (const char *msg)
{
- message ("%s", msg);
+ message1 (msg);
}
VOL must be an integer in the range [0, 100], or a float in the
range [0, 1]. */
-static int
+static bool
parse_sound (Lisp_Object sound, Lisp_Object *attrs)
{
/* SOUND must be a list starting with the symbol `sound'. */
/* BEGIN: Non Windows functions */
#ifndef WINDOWSNT
+/* Return S's value as a string if S is a string, otherwise DEFAULT_VALUE. */
+
+static char const *
+string_default (Lisp_Object s, char const *default_value)
+{
+ return STRINGP (s) ? SSDATA (s) : default_value;
+}
+
+
/* Find out the type of the sound file whose file descriptor is FD.
S is the sound file structure to fill in. */
}
-/* Function installed by play-sound-internal with record_unwind_protect. */
+/* Function installed by play-sound-internal with record_unwind_protect_void. */
-static Lisp_Object
-sound_cleanup (Lisp_Object arg)
+static void
+sound_cleanup (void)
{
if (current_sound_device->close)
current_sound_device->close (current_sound_device);
emacs_close (current_sound->fd);
xfree (current_sound_device);
xfree (current_sound);
-
- return Qnil;
}
/***********************************************************************
le2hl (u_int32_t value)
{
#ifdef WORDS_BIGENDIAN
- unsigned char *p = (unsigned char *) &value;
- value = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
+ value = bswap_32 (value);
#endif
return value;
}
le2hs (u_int16_t value)
{
#ifdef WORDS_BIGENDIAN
- unsigned char *p = (unsigned char *) &value;
- value = p[0] + (p[1] << 8);
+ value = bswap_16 (value);
#endif
return value;
}
be2hl (u_int32_t value)
{
#ifndef WORDS_BIGENDIAN
- unsigned char *p = (unsigned char *) &value;
- value = p[3] + (p[2] << 8) + (p[1] << 16) + (p[0] << 24);
-#endif
- return value;
-}
-
-
-#if 0 /* Currently not used. */
-
-/* Convert 16-bit value VALUE which is in big-endian byte-order
- to host byte-order. */
-
-static u_int16_t
-be2hs (u_int16_t value)
-{
-#ifndef WORDS_BIGENDIAN
- unsigned char *p = (unsigned char *) &value;
- value = p[1] + (p[0] << 8);
+ value = bswap_32 (value);
#endif
return value;
}
-#endif /* 0 */
-
/***********************************************************************
RIFF-WAVE (*.wav)
***********************************************************************/
contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
sound file. If the file is a WAV-format file, set up interface
functions in S and convert header fields to host byte-order.
- Value is non-zero if the file is a WAV file. */
+ Value is true if the file is a WAV file. */
-static int
+static bool
wav_init (struct sound *s)
{
struct wav_header *header = (struct wav_header *) s->header;
SBYTES (s->data) - sizeof *header);
else
{
- char *buffer;
- EMACS_INT nbytes = 0;
- EMACS_INT blksize = sd->period_size ? sd->period_size (sd) : 2048;
- EMACS_INT data_left = header->data_length;
-
- buffer = (char *) alloca (blksize);
+ ptrdiff_t nbytes = 0;
+ ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
+ ptrdiff_t data_left = header->data_length;
+ USE_SAFE_ALLOCA;
+ char *buffer = SAFE_ALLOCA (blksize);
lseek (s->fd, sizeof *header, SEEK_SET);
while (data_left > 0
&& (nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
if (nbytes < 0)
sound_perror ("Error reading sound file");
+ SAFE_FREE ();
}
}
contains the first MAX_SOUND_HEADER_BYTES number of bytes from the
sound file. If the file is a AU-format file, set up interface
functions in S and convert header fields to host byte-order.
- Value is non-zero if the file is an AU file. */
+ Value is true if the file is an AU file. */
-static int
+static bool
au_init (struct sound *s)
{
struct au_header *header = (struct au_header *) s->header;
SBYTES (s->data) - header->data_offset);
else
{
- EMACS_INT blksize = sd->period_size ? sd->period_size (sd) : 2048;
- char *buffer;
- EMACS_INT nbytes;
+ ptrdiff_t blksize = sd->period_size ? sd->period_size (sd) : 2048;
+ ptrdiff_t nbytes;
/* Seek */
lseek (s->fd, header->data_offset, SEEK_SET);
/* Copy sound data to the device. */
- buffer = (char *) alloca (blksize);
+ USE_SAFE_ALLOCA;
+ char *buffer = SAFE_ALLOCA (blksize);
while ((nbytes = emacs_read (s->fd, buffer, blksize)) > 0)
sd->write (sd, buffer, nbytes);
if (nbytes < 0)
sound_perror ("Error reading sound file");
+ SAFE_FREE ();
}
}
has a compatible own driver aka Luigi's driver. */
-/* Open device SD. If SD->file is non-null, open that device,
+/* Open device SD. If SD->file is a string, open that device,
otherwise use a default device name. */
static void
vox_open (struct sound_device *sd)
{
- const char *file;
-
- /* Open the sound device. Default is /dev/dsp. */
- if (sd->file)
- file = sd->file;
- else
- file = DEFAULT_SOUND_DEVICE;
-
+ /* Open the sound device (eg /dev/dsp). */
+ char const *file = string_default (sd->file, DEFAULT_SOUND_DEVICE);
sd->fd = emacs_open (file, O_WRONLY, 0);
if (sd->fd < 0)
sound_perror (file);
vox_configure (struct sound_device *sd)
{
int val;
+#ifdef USABLE_SIGIO
+ sigset_t oldset, 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, &oldset);
#endif
val = sd->format;
}
turn_on_atimers (1);
-#ifdef SIGIO
- sigunblock (sigmask (SIGIO));
+#ifdef USABLE_SIGIO
+ pthread_sigmask (SIG_SETMASK, &oldset, 0);
#endif
}
/* 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, oldset;
+ sigemptyset (&blocked);
+ sigaddset (&blocked, SIGIO);
+ pthread_sigmask (SIG_BLOCK, &blocked, &oldset);
#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_SETMASK, &oldset, 0);
#endif
/* Close the device. */
}
}
else
- abort ();
+ emacs_abort ();
}
/* Initialize device SD. Set up the interface functions in the device
structure. */
-static int
+static bool
vox_init (struct sound_device *sd)
{
- const char *file;
- int fd;
-
- /* Open the sound device. Default is /dev/dsp. */
- if (sd->file)
- file = sd->file;
- else
- file = DEFAULT_SOUND_DEVICE;
- fd = emacs_open (file, O_WRONLY, 0);
+ /* Open the sound device (eg /dev/dsp). */
+ char const *file = string_default (sd->file, DEFAULT_SOUND_DEVICE);
+ int fd = emacs_open (file, O_WRONLY, 0);
if (fd >= 0)
emacs_close (fd);
else
/* Write NBYTES bytes from BUFFER to device SD. */
static void
-vox_write (struct sound_device *sd, const char *buffer, EMACS_INT nbytes)
+vox_write (struct sound_device *sd, const char *buffer, ptrdiff_t nbytes)
{
- if (emacs_write (sd->fd, buffer, nbytes) != nbytes)
+ if (emacs_write_sig (sd->fd, buffer, nbytes) != nbytes)
sound_perror ("Error writing to sound device");
}
/* This driver is available on GNU/Linux. */
-static void
+#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));
snd_pcm_uframes_t period_size;
};
-/* Open device SD. If SD->file is non-null, open that device,
+/* Open device SD. If SD->file is a string, open that device,
otherwise use a default device name. */
static void
alsa_open (struct sound_device *sd)
{
- const char *file;
- struct alsa_params *p;
- int err;
-
/* Open the sound device. Default is "default". */
- if (sd->file)
- file = sd->file;
- else
- file = DEFAULT_ALSA_SOUND_DEVICE;
+ struct alsa_params *p = xmalloc (sizeof *p);
+ char const *file = string_default (sd->file, DEFAULT_ALSA_SOUND_DEVICE);
+ int err;
- p = xmalloc (sizeof (*p));
p->handle = NULL;
p->hwparams = NULL;
p->swparams = NULL;
alsa_sound_perror (file, err);
}
-static EMACS_INT
+static ptrdiff_t
alsa_period_size (struct sound_device *sd)
{
struct alsa_params *p = (struct alsa_params *) sd->data;
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)
int chn;
snd_mixer_t *handle;
snd_mixer_elem_t *e;
- const char *file = sd->file ? sd->file : DEFAULT_ALSA_SOUND_DEVICE;
-
if (snd_mixer_open (&handle, 0) >= 0)
{
+ char const *file = string_default (sd->file,
+ DEFAULT_ALSA_SOUND_DEVICE);
if (snd_mixer_attach (handle, file) >= 0
&& snd_mixer_load (handle) >= 0
&& snd_mixer_selem_register (handle, NULL, NULL) >= 0)
}
}
else
- abort ();
+ emacs_abort ();
}
/* Write NBYTES bytes from BUFFER to device SD. */
static void
-alsa_write (struct sound_device *sd, const char *buffer, EMACS_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;
- EMACS_INT nwritten = 0;
+ ptrdiff_t nwritten = 0;
int err;
while (nwritten < nbytes)
/* Initialize device SD. Set up the interface functions in the device
structure. */
-static int
+static bool
alsa_init (struct sound_device *sd)
{
- const char *file;
+ /* Open the sound device. Default is "default". */
+ char const *file = string_default (sd->file, DEFAULT_ALSA_SOUND_DEVICE);
snd_pcm_t *handle;
int err;
- /* Open the sound device. Default is "default". */
- if (sd->file)
- file = sd->file;
- else
- file = DEFAULT_ALSA_SOUND_DEVICE;
-
snd_lib_error_set_handler ((snd_lib_error_handler_t) snd_error_quiet);
err = snd_pcm_open (&handle, file, SND_PCM_STREAM_PLAYBACK, 0);
snd_lib_error_set_handler (NULL);
/* BEGIN: Windows specific functions */
-#define SOUND_WARNING(fun, error, text) \
- { \
- char buf[1024]; \
- char err_string[MAXERRORLENGTH]; \
- fun (error, err_string, sizeof (err_string)); \
- _snprintf (buf, sizeof (buf), "%s\nError: %s", \
- text, err_string); \
- sound_warning (buf); \
- }
+#define SOUND_WARNING(func, error, text) \
+ do { \
+ char buf[1024]; \
+ char err_string[MAXERRORLENGTH]; \
+ func (error, err_string, sizeof (err_string)); \
+ _snprintf (buf, sizeof (buf), "%s\nMCI Error: %s", \
+ text, err_string); \
+ message_with_string ("%s", build_string (buf), 1); \
+ } while (0)
static int
do_play_sound (const char *psz_file, unsigned long ui_volume)
{
int i_result = 0;
MCIERROR mci_error = 0;
- char sz_cmd_buf[520] = {0};
- char sz_ret_buf[520] = {0};
+ char sz_cmd_buf_a[520];
+ char sz_ret_buf_a[520];
MMRESULT mm_result = MMSYSERR_NOERROR;
unsigned long ui_volume_org = 0;
BOOL b_reset_volume = FALSE;
+ char warn_text[560];
+
+ /* Since UNICOWS.DLL includes only a stub for mciSendStringW, we
+ need to encode the file in the ANSI codepage on Windows 9X even
+ if w32_unicode_filenames is non-zero. */
+ if (w32_major_version <= 4 || !w32_unicode_filenames)
+ {
+ char fname_a[MAX_PATH], shortname[MAX_PATH], *fname_to_use;
+
+ filename_to_ansi (psz_file, fname_a);
+ fname_to_use = fname_a;
+ /* If the file name is not encodable in ANSI, try its short 8+3
+ alias. This will only work if w32_unicode_filenames is
+ non-zero. */
+ if (_mbspbrk ((const unsigned char *)fname_a,
+ (const unsigned char *)"?"))
+ {
+ if (w32_get_short_filename (psz_file, shortname, MAX_PATH))
+ fname_to_use = shortname;
+ else
+ mci_error = MCIERR_FILE_NOT_FOUND;
+ }
- memset (sz_cmd_buf, 0, sizeof (sz_cmd_buf));
- memset (sz_ret_buf, 0, sizeof (sz_ret_buf));
- sprintf (sz_cmd_buf,
- "open \"%s\" alias GNUEmacs_PlaySound_Device wait",
- psz_file);
- mci_error = mciSendString (sz_cmd_buf, sz_ret_buf, sizeof (sz_ret_buf), NULL);
+ if (!mci_error)
+ {
+ memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a));
+ memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a));
+ sprintf (sz_cmd_buf_a,
+ "open \"%s\" alias GNUEmacs_PlaySound_Device wait",
+ fname_to_use);
+ mci_error = mciSendStringA (sz_cmd_buf_a,
+ sz_ret_buf_a, sizeof (sz_ret_buf_a), NULL);
+ }
+ }
+ else
+ {
+ wchar_t sz_cmd_buf_w[520];
+ wchar_t sz_ret_buf_w[520];
+ wchar_t fname_w[MAX_PATH];
+
+ filename_to_utf16 (psz_file, fname_w);
+ memset (sz_cmd_buf_w, 0, sizeof (sz_cmd_buf_w));
+ memset (sz_ret_buf_w, 0, sizeof (sz_ret_buf_w));
+ /* _swprintf is not available on Windows 9X, so we construct the
+ UTF-16 command string by hand. */
+ wcscpy (sz_cmd_buf_w, L"open \"");
+ wcscat (sz_cmd_buf_w, fname_w);
+ wcscat (sz_cmd_buf_w, L"\" alias GNUEmacs_PlaySound_Device wait");
+ mci_error = mciSendStringW (sz_cmd_buf_w,
+ sz_ret_buf_w, ARRAYELTS (sz_ret_buf_w) , NULL);
+ }
if (mci_error != 0)
{
- SOUND_WARNING (mciGetErrorString, mci_error,
- "The open mciSendString command failed to open "
- "the specified sound file.");
+ strcpy (warn_text,
+ "mciSendString: 'open' command failed to open sound file ");
+ strcat (warn_text, psz_file);
+ SOUND_WARNING (mciGetErrorString, mci_error, warn_text);
i_result = (int) mci_error;
return i_result;
}
if (mm_result != MMSYSERR_NOERROR)
{
SOUND_WARNING (waveOutGetErrorText, mm_result,
- "waveOutSetVolume failed to set the volume level "
- "of the WAVE_MAPPER device.\n"
- "As a result, the user selected volume level will "
- "not be used.");
+ "waveOutSetVolume: failed to set the volume level"
+ " of the WAVE_MAPPER device.\n"
+ "As a result, the user selected volume level will"
+ " not be used.");
}
}
else
{
SOUND_WARNING (waveOutGetErrorText, mm_result,
- "waveOutGetVolume failed to obtain the original "
- "volume level of the WAVE_MAPPER device.\n"
- "As a result, the user selected volume level will "
- "not be used.");
+ "waveOutGetVolume: failed to obtain the original"
+ " volume level of the WAVE_MAPPER device.\n"
+ "As a result, the user selected volume level will"
+ " not be used.");
}
}
- memset (sz_cmd_buf, 0, sizeof (sz_cmd_buf));
- memset (sz_ret_buf, 0, sizeof (sz_ret_buf));
- strcpy (sz_cmd_buf, "play GNUEmacs_PlaySound_Device wait");
- mci_error = mciSendString (sz_cmd_buf, sz_ret_buf, sizeof (sz_ret_buf), NULL);
+ memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a));
+ memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a));
+ strcpy (sz_cmd_buf_a, "play GNUEmacs_PlaySound_Device wait");
+ mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a),
+ NULL);
if (mci_error != 0)
{
- SOUND_WARNING (mciGetErrorString, mci_error,
- "The play mciSendString command failed to play the "
- "opened sound file.");
+ strcpy (warn_text,
+ "mciSendString: 'play' command failed to play sound file ");
+ strcat (warn_text, psz_file);
+ SOUND_WARNING (mciGetErrorString, mci_error, warn_text);
i_result = (int) mci_error;
}
- memset (sz_cmd_buf, 0, sizeof (sz_cmd_buf));
- memset (sz_ret_buf, 0, sizeof (sz_ret_buf));
- strcpy (sz_cmd_buf, "close GNUEmacs_PlaySound_Device wait");
- mci_error = mciSendString (sz_cmd_buf, sz_ret_buf, sizeof (sz_ret_buf), NULL);
+ memset (sz_cmd_buf_a, 0, sizeof (sz_cmd_buf_a));
+ memset (sz_ret_buf_a, 0, sizeof (sz_ret_buf_a));
+ strcpy (sz_cmd_buf_a, "close GNUEmacs_PlaySound_Device wait");
+ mci_error = mciSendStringA (sz_cmd_buf_a, sz_ret_buf_a, sizeof (sz_ret_buf_a),
+ NULL);
if (b_reset_volume == TRUE)
{
mm_result = waveOutSetVolume ((HWAVEOUT) WAVE_MAPPER, ui_volume_org);
if (mm_result != MMSYSERR_NOERROR)
{
SOUND_WARNING (waveOutGetErrorText, mm_result,
- "waveOutSetVolume failed to reset the original volume "
- "level of the WAVE_MAPPER device.");
+ "waveOutSetVolume: failed to reset the original"
+ " volume level of the WAVE_MAPPER device.");
}
}
return i_result;
(Lisp_Object sound)
{
Lisp_Object attrs[SOUND_ATTR_SENTINEL];
- int count = SPECPDL_INDEX ();
-
-#ifndef WINDOWSNT
+ ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object file;
- struct gcpro gcpro1, gcpro2;
Lisp_Object args[2];
-#else /* WINDOWSNT */
- int len = 0;
- Lisp_Object lo_file = {0};
- char * psz_file = NULL;
+ struct gcpro gcpro1, gcpro2;
+
+#ifdef WINDOWSNT
unsigned long ui_volume_tmp = UINT_MAX;
unsigned long ui_volume = UINT_MAX;
- int i_result = 0;
#endif /* WINDOWSNT */
/* Parse the sound specification. Give up if it is invalid. */
#ifndef WINDOWSNT
file = Qnil;
GCPRO2 (sound, file);
- current_sound_device = (struct sound_device *) xmalloc (sizeof (struct sound_device));
- memset (current_sound_device, 0, sizeof (struct sound_device));
- current_sound = (struct sound *) xmalloc (sizeof (struct sound));
- memset (current_sound, 0, sizeof (struct sound));
- record_unwind_protect (sound_cleanup, Qnil);
- current_sound->header = (char *) alloca (MAX_SOUND_HEADER_BYTES);
+ current_sound_device = xzalloc (sizeof *current_sound_device);
+ current_sound = xzalloc (sizeof *current_sound);
+ record_unwind_protect_void (sound_cleanup);
+ char headerbuf[MAX_SOUND_HEADER_BYTES];
+ current_sound->header = headerbuf;
if (STRINGP (attrs[SOUND_FILE]))
{
/* Open the sound file. */
- current_sound->fd = openp (Fcons (Vdata_directory, Qnil),
- attrs[SOUND_FILE], Qnil, &file, Qnil);
+ current_sound->fd = openp (list1 (Vdata_directory),
+ attrs[SOUND_FILE], Qnil, &file, Qnil, false);
if (current_sound->fd < 0)
sound_perror ("Could not open sound file");
find_sound_type (current_sound);
/* Set up a device. */
- if (STRINGP (attrs[SOUND_DEVICE]))
- {
- int len = SCHARS (attrs[SOUND_DEVICE]);
- current_sound_device->file = (char *) alloca (len + 1);
- strcpy (current_sound_device->file, SSDATA (attrs[SOUND_DEVICE]));
- }
+ current_sound_device->file = attrs[SOUND_DEVICE];
if (INTEGERP (attrs[SOUND_VOLUME]))
current_sound_device->volume = XFASTINT (attrs[SOUND_VOLUME]);
#else /* WINDOWSNT */
- lo_file = Fexpand_file_name (attrs[SOUND_FILE], Qnil);
- len = XSTRING (lo_file)->size;
- psz_file = (char *) alloca (len + 1);
- strcpy (psz_file, XSTRING (lo_file)->data);
+ file = Fexpand_file_name (attrs[SOUND_FILE], Vdata_directory);
+ file = ENCODE_FILE (file);
if (INTEGERP (attrs[SOUND_VOLUME]))
{
ui_volume_tmp = XFASTINT (attrs[SOUND_VOLUME]);
{
ui_volume_tmp = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
}
+
+ GCPRO2 (sound, file);
+
+ args[0] = Qplay_sound_functions;
+ args[1] = sound;
+ Frun_hook_with_args (2, args);
+
/*
Based on some experiments I have conducted, a value of 100 or less
for the sound volume is much too low. You cannot even hear it.
{
ui_volume = ui_volume_tmp * (UINT_MAX / 100);
}
- i_result = do_play_sound (psz_file, ui_volume);
+ (void)do_play_sound (SSDATA (file), ui_volume);
+
+ UNGCPRO;
#endif /* WINDOWSNT */
defsubr (&Splay_sound_internal);
}
-
-void
-init_sound (void)
-{
-}
-
#endif /* HAVE_SOUND */