Commit f60ae425 authored by Ben Key's avatar Ben Key

Added a partial implementation of play-sound-internal for Windows. Fixed the...

Added a partial implementation of play-sound-internal for Windows.  Fixed the following entry in etc/PROBLEMS: Emacs built on Windows 9x/ME crashes at startup on Windows XP, or Emacs built on XP crashes at startup on Windows 9x/ME.
parent 87a609d3
2002-11-17 Ben Key <BKey1@tampabay.rr.com>
* nmake.defs: Made changes so that Emacs would link with
WinMM.lib. This change was required for my addition of a Windows
compatible implementation of play-sound-internal.
* gmake.defs: Made changes so that Emacs would link with
WinMM.lib. This change was required for my addition of a Windows
compatible implementation of play-sound-internal.
2002-09-03 Juanma Barranquero <lektu@terra.es> (tiny change)
* emacs.rc: Version updated to 21.3.50. From Peter Runestig
......
......@@ -166,6 +166,7 @@ MPR = -lmpr
SHELL32 = -lshell32
USER32 = -luser32
WSOCK32 = -lwsock32
WINMM = -lwinmm
ifdef NOOPT
DEBUG_CFLAGS = -DEMACSDEBUG
......
......@@ -123,6 +123,7 @@ MPR = mpr.lib
SHELL32 = shell32.lib
USER32 = user32.lib
WSOCK32 = wsock32.lib
WINMM = winmm.lib
!ifdef NOOPT
DEBUG_CFLAGS = -DEMACSDEBUG
......
2002-11-17 Ben Key <BKey1@tampabay.rr.com>
* w32.c: Added wrapper functions around the win32 API functions
OpenProcessToken, GetTokenInformation, LookupAccountSid, and
GetSidIdentifierAuthority. These wrapper functions serve two
purposes:
1. They ensure that the wrapped function can never be called
when Emacs is running on an operating system on which they are
not supported (Microsoft Windows 95 / 98 / ME).
2. They call the wrapped functions via function pointers rather
than calling them directly. This avoids taking advantage of the
undocumented fact that although these functions are not supported
in the 9x branch of Microsoft Windows, the functions do exist in
the version of advapi32.dll that is found in the 9x branch of
Microsoft Windows.
This change is part of my fix for the following entry in
etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on
Windows XP, or Emacs built on XP crashes at startup on Windows
9x/ME."
* w32.c (init_user_info): Replaced the calls to the win32 API
functions OpenProcessToken, GetTokenInformation, LookupAccountSid,
and GetSidIdentifierAuthority with calls to the newly added
wrapper functions.
This change is part of my fix for the following entry in
etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on
Windows XP, or Emacs built on XP crashes at startup on Windows
9x/ME."
* w32.h: Added extern declarations for the following functions:
syms_of_w32term, syms_of_w32fns, syms_of_w32select,
syms_of_w32menu, and void syms_of_fontset.
This change is part of my fix for the following entry in
etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on
Windows XP, or Emacs built on XP crashes at startup on Windows
9x/ME."
* w32fns.c (w32_wnd_proc): Added code to reinitialize the
function pointer track_mouse_event_fn in the handler for the
WM_SETFOCUS message.
This change is part of my fix for the following entry in
etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on
Windows XP, or Emacs built on XP crashes at startup on Windows
9x/ME."
* w32menu.c (initialize_frame_menubar): Added code to
reinitialize the function pointers set_menu_item_info and
get_menu_item_info.
This change is part of my fix for the following entry in
etc/PROBLEMS: "Emacs built on Windows 9x/ME crashes at startup on
Windows XP, or Emacs built on XP crashes at startup on Windows
9x/ME."
* sound.c: Added a partial implementation of play-sound-internal
for Microsoft Windows. Added various #ifdef / #else / #endif
code blocks to separate the code that will compile under
Microsoft Windows from the code that is specific to Gnu/Linux.
Moved several blocks of code around to make this separation of
code into Windows compatible and Gnu/Linux compatible code blocks
easier.
* makefile.w32-in: Made modifications so that sound.c would be
included in the Windows port of Emacs and that it would link with
WinMM.lib.
* s/ms-w32.h: Defined the symbol HAVE_SOUND so that the newly
added support for play-sound-internal under Windows would be
included in the build of Emacs.
2002-11-16 Jason Rumney <jasonr@gnu.org>
* w32fns.c (w32_load_system_font): Don't disable Cleartype.
......
......@@ -94,6 +94,7 @@ OBJ1 = $(BLD)/abbrev.$(O) \
$(BLD)/regex.$(O) \
$(BLD)/scroll.$(O) \
$(BLD)/search.$(O) \
$(BLD)/sound.$(O) \
$(BLD)/syntax.$(O) \
$(BLD)/sysdep.$(O) \
$(BLD)/term.$(O) \
......@@ -133,6 +134,7 @@ LIBS = $(TLIB0) \
$(TLIB1) \
$(TLIBW32) \
$(TLASTLIB) \
$(WINMM) \
$(ADVAPI32) \
$(GDI32) \
$(COMDLG32) \
......@@ -1094,6 +1096,13 @@ $(BLD)/search.$(O) : \
$(SRC)/w32bdf.h \
$(SRC)/w32gui.h
$(BLD)/sound.$(O) : \
$(SRC)/sound.c \
$(SRC)/lisp.h \
$(SRC)/dispextern.h \
$(SRC)/atimer.h \
$(SRC)/syssignal.h
$(BLD)/strftime.$(O) : \
$(SRC)/strftime.c \
$(EMACS_ROOT)/src/s/ms-w32.h \
......
......@@ -217,6 +217,7 @@ Boston, MA 02111-1307, USA. */
#define MAXPATHLEN _MAX_PATH
#endif
#define HAVE_SOUND 1
#define LISP_FLOAT_TYPE 1
#undef HAVE_SYS_SELECT_H
......
......@@ -21,10 +21,26 @@ Boston, MA 02111-1307, USA. */
/* Written by Gerd Moellmann <gerd@gnu.org>. Tested with Luigi's
driver on FreeBSD 2.2.7 with a SoundBlaster 16. */
/*
Modified by Ben Key <Bkey1@tampabay.rr.com> to add a partial
implementation of the play-sound specification for Windows.
Notes:
In the Windows implementation of play-sound-internal only the
:file and :volume keywords are supported. The :device keyword,
if present, is ignored. The :data keyword, if present, will
cause an error to be generated.
The Windows implementation of play-sound is implemented via the
Win32 API functions mciSendString, waveOutGetVolume, and
waveOutGetVolume which are exported by Winmm.dll.
*/
#include <config.h>
#if defined HAVE_SOUND
/* BEGIN: Common Includes */
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
......@@ -34,6 +50,11 @@ Boston, MA 02111-1307, USA. */
#include "atimer.h"
#include <signal.h>
#include "syssignal.h"
/* END: Common Includes */
/* BEGIN: Non Windows Includes */
#ifndef WINDOWSNT
#ifndef MSDOS
#include <sys/ioctl.h>
......@@ -51,12 +72,55 @@ Boston, MA 02111-1307, USA. */
#ifdef HAVE_SOUNDCARD_H
#include <soundcard.h>
#endif
/* END: Non Windows Includes */
#else /* WINDOWSNT */
/* BEGIN: Windows Specific Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <windows.h>
#include <mmsystem.h>
/* END: Windows Specific Includes */
#endif /* WINDOWSNT */
/* BEGIN: Common Definitions */
#define abs(X) ((X) < 0 ? -(X) : (X))
/* Symbols. */
extern Lisp_Object QCfile, QCdata;
Lisp_Object QCvolume, QCdevice;
Lisp_Object Qsound;
Lisp_Object Qplay_sound_functions;
/* Indices of attributes in a sound attributes vector. */
enum sound_attr
{
SOUND_FILE,
SOUND_DATA,
SOUND_DEVICE,
SOUND_VOLUME,
SOUND_ATTR_SENTINEL
};
static void sound_perror P_ ((char *));
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
#define abs(X) ((X) < 0 ? -(X) : (X))
/* Structure forward declarations. */
......@@ -203,24 +267,6 @@ struct sound
void (* play) P_ ((struct sound *s, struct sound_device *sd));
};
/* Indices of attributes in a sound attributes vector. */
enum sound_attr
{
SOUND_FILE,
SOUND_DATA,
SOUND_DEVICE,
SOUND_VOLUME,
SOUND_ATTR_SENTINEL
};
/* Symbols. */
extern Lisp_Object QCfile, QCdata;
Lisp_Object QCvolume, QCdevice;
Lisp_Object Qsound;
Lisp_Object Qplay_sound_functions;
/* These are set during `play-sound-internal' so that sound_cleanup has
access to them. */
......@@ -235,9 +281,6 @@ static void vox_close P_ ((struct sound_device *sd));
static void vox_choose_format P_ ((struct sound_device *, struct sound *));
static void vox_init P_ ((struct sound_device *));
static void vox_write P_ ((struct sound_device *, const char *, int));
static void sound_perror P_ ((char *));
static void sound_warning P_ ((char *));
static int parse_sound P_ ((Lisp_Object, Lisp_Object *));
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));
......@@ -251,12 +294,22 @@ static void au_play P_ ((struct sound *, struct sound_device *));
static u_int16_t be2hs P_ ((u_int16_t));
#endif
/* END: Non Windows Definitions */
#else /* WINDOWSNT */
/* BEGIN: Windows Specific Definitions */
static int do_play_sound P_ ((const char *, unsigned long));
/*
END: Windows Specific Definitions */
#endif /* WINDOWSNT */
/***********************************************************************
General
***********************************************************************/
/* BEGIN: Common functions */
/* Like perror, but signals an error. */
static void
......@@ -327,10 +380,21 @@ parse_sound (sound, attrs)
attrs[SOUND_DEVICE] = Fplist_get (sound, QCdevice);
attrs[SOUND_VOLUME] = Fplist_get (sound, QCvolume);
#ifndef WINDOWSNT
/* File name or data must be specified. */
if (!STRINGP (attrs[SOUND_FILE])
&& !STRINGP (attrs[SOUND_DATA]))
return 0;
#else /* WINDOWSNT */
/*
Data is not supported in Windows. Therefore a
File name MUST be supplied.
*/
if (!STRINGP (attrs[SOUND_FILE]))
{
return 0;
}
#endif /* WINDOWSNT */
/* Volume must be in the range 0..100 or unspecified. */
if (!NILP (attrs[SOUND_VOLUME]))
......@@ -351,14 +415,23 @@ parse_sound (sound, attrs)
return 0;
}
#ifndef WINDOWSNT
/* Device must be a string or unspecified. */
if (!NILP (attrs[SOUND_DEVICE])
&& !STRINGP (attrs[SOUND_DEVICE]))
return 0;
#endif /* WINDOWSNT */
/*
Since device is ignored in Windows, it does not matter
what it is.
*/
return 1;
}
/* END: Common functions */
/* BEGIN: Non Windows functions */
#ifndef WINDOWSNT
/* Find out the type of the sound file whose file descriptor is FD.
S is the sound file structure to fill in. */
......@@ -389,105 +462,6 @@ sound_cleanup (arg)
return Qnil;
}
DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1, 0,
doc: /* Play sound SOUND.
Internal use only, use `play-sound' instead. */)
(sound)
Lisp_Object sound;
{
Lisp_Object attrs[SOUND_ATTR_SENTINEL];
Lisp_Object file;
struct gcpro gcpro1, gcpro2;
struct sound_device sd;
struct sound s;
Lisp_Object args[2];
int count = SPECPDL_INDEX ();
file = Qnil;
GCPRO2 (sound, file);
bzero (&sd, sizeof sd);
bzero (&s, sizeof s);
current_sound_device = &sd;
current_sound = &s;
record_unwind_protect (sound_cleanup, Qnil);
s.header = (char *) alloca (MAX_SOUND_HEADER_BYTES);
/* Parse the sound specification. Give up if it is invalid. */
if (!parse_sound (sound, attrs))
error ("Invalid sound specification");
if (STRINGP (attrs[SOUND_FILE]))
{
/* Open the sound file. */
s.fd = openp (Fcons (Vdata_directory, Qnil),
attrs[SOUND_FILE], Qnil, &file, Qnil);
if (s.fd < 0)
sound_perror ("Could not open sound file");
/* Read the first bytes from the file. */
s.header_size = emacs_read (s.fd, s.header, MAX_SOUND_HEADER_BYTES);
if (s.header_size < 0)
sound_perror ("Invalid sound file header");
}
else
{
s.data = attrs[SOUND_DATA];
s.header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (s.data));
bcopy (SDATA (s.data), s.header, s.header_size);
}
/* Find out the type of sound. Give up if we can't tell. */
find_sound_type (&s);
/* Set up a device. */
if (STRINGP (attrs[SOUND_DEVICE]))
{
int len = SCHARS (attrs[SOUND_DEVICE]);
sd.file = (char *) alloca (len + 1);
strcpy (sd.file, SDATA (attrs[SOUND_DEVICE]));
}
if (INTEGERP (attrs[SOUND_VOLUME]))
sd.volume = XFASTINT (attrs[SOUND_VOLUME]);
else if (FLOATP (attrs[SOUND_VOLUME]))
sd.volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
args[0] = Qplay_sound_functions;
args[1] = sound;
Frun_hook_with_args (2, args);
/* There is only one type of device we currently support, the VOX
sound driver. Set up the device interface functions for that
device. */
vox_init (&sd);
/* Open the device. */
sd.open (&sd);
/* Play the sound. */
s.play (&s, &sd);
/* Close the input file, if any. */
if (!STRINGP (s.data))
{
emacs_close (s.fd);
s.fd = -1;
}
/* Close the device. */
sd.close (&sd);
/* Clean up. */
current_sound_device = NULL;
current_sound = NULL;
UNGCPRO;
unbind_to (count, Qnil);
return Qnil;
}
/***********************************************************************
Byte-order Conversion
***********************************************************************/
......@@ -555,7 +529,6 @@ be2hs (value)
#endif /* 0 */
/***********************************************************************
RIFF-WAVE (*.wav)
***********************************************************************/
......@@ -645,7 +618,6 @@ wav_play (s, sd)
}
/***********************************************************************
Sun Audio (*.au)
***********************************************************************/
......@@ -735,7 +707,6 @@ au_play (s, sd)
}
/***********************************************************************
Voxware Driver Interface
***********************************************************************/
......@@ -909,7 +880,6 @@ vox_init (sd)
sd->write = vox_write;
}
/* Write NBYTES bytes from BUFFER to device SD. */
static void
......@@ -923,7 +893,231 @@ vox_write (sd, buffer, nbytes)
sound_perror ("Error writing to sound device");
}
/* END: Non Windows functions */
#else /* WINDOWSNT */
/* BEGIN: Windows specific functions */
static int
do_play_sound (psz_file, ui_volume)
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};
MMRESULT mm_result=MMSYSERR_NOERROR;
unsigned long ui_volume_org=0;
BOOL b_reset_volume=FALSE;
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, 520, NULL);
if (mci_error != 0)
{
sound_warning (
"The open mciSendString command failed to open\n"
"the specified sound file");
i_result=(int)mci_error;
return i_result;
}
if ((ui_volume > 0) && (ui_volume != UINT_MAX))
{
mm_result=waveOutGetVolume ((HWAVEOUT)WAVE_MAPPER, &ui_volume_org);
if (mm_result == MMSYSERR_NOERROR)
{
b_reset_volume=TRUE;
mm_result=waveOutSetVolume ((HWAVEOUT)WAVE_MAPPER, ui_volume);
if ( mm_result != MMSYSERR_NOERROR)
{
sound_warning (
"waveOutSetVolume failed to set the volume level\n"
"of the WAVE_MAPPER device.\n"
"As a result, the user selected volume level will\n"
"not be used.");
}
}
else
{
sound_warning (
"waveOutGetVolume failed to obtain the original\n"
"volume level of the WAVE_MAPPER device.\n"
"As a result, the user selected volume level will\n"
"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, 520, NULL);
if (mci_error != 0)
{
sound_warning (
"The play mciSendString command failed to play the\n"
"opened sound file.");
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, 520, NULL);
if (b_reset_volume == TRUE)
{
mm_result=waveOutSetVolume ((HWAVEOUT)WAVE_MAPPER, ui_volume_org);
if (mm_result != MMSYSERR_NOERROR)
{
sound_warning (
"waveOutSetVolume failed to reset the original volume\n"
"level of the WAVE_MAPPER device.");
}
}
return i_result;
}
/* END: Windows specific functions */
#endif /* WINDOWSNT */
DEFUN ("play-sound-internal", Fplay_sound_internal, Splay_sound_internal, 1, 1, 0,
doc: /* Play sound SOUND.
Internal use only, use `play-sound' instead.\n */)
(sound)
Lisp_Object sound;
{
Lisp_Object attrs[SOUND_ATTR_SENTINEL];
int count = SPECPDL_INDEX ();
#ifndef WINDOWSNT
Lisp_Object file;
struct gcpro gcpro1, gcpro2;
struct sound_device sd;
struct sound s;
Lisp_Object args[2];
#else /* WINDOWSNT */
int len=0;
Lisp_Object lo_file={0};
char * psz_file=NULL;
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. */
if (!parse_sound (sound, attrs))
error ("Invalid sound specification");
#ifndef WINDOWSNT
file = Qnil;
GCPRO2 (sound, file);
bzero (&sd, sizeof sd);
bzero (&s, sizeof s);
current_sound_device = &sd;
current_sound = &s;
record_unwind_protect (sound_cleanup, Qnil);
s.header = (char *) alloca (MAX_SOUND_HEADER_BYTES);
if (STRINGP (attrs[SOUND_FILE]))
{
/* Open the sound file. */
s.fd = openp (Fcons (Vdata_directory, Qnil),
attrs[SOUND_FILE], Qnil, &file, Qnil);
if (s.fd < 0)
sound_perror ("Could not open sound file");
/* Read the first bytes from the file. */
s.header_size = emacs_read (s.fd, s.header, MAX_SOUND_HEADER_BYTES);
if (s.header_size < 0)
sound_perror ("Invalid sound file header");
}
else
{
s.data = attrs[SOUND_DATA];
s.header_size = min (MAX_SOUND_HEADER_BYTES, SBYTES (s.data));
bcopy (SDATA (s.data), s.header, s.header_size);
}
/* Find out the type of sound. Give up if we can't tell. */
find_sound_type (&s);
/* Set up a device. */
if (STRINGP (attrs[SOUND_DEVICE]))
{
int len = SCHARS (attrs[SOUND_DEVICE]);
sd.file = (char *) alloca (len + 1);
strcpy (sd.file, SDATA (attrs[SOUND_DEVICE]));
}
if (INTEGERP (attrs[SOUND_VOLUME]))
sd.volume = XFASTINT (attrs[SOUND_VOLUME]);
else if (FLOATP (attrs[SOUND_VOLUME]))
sd.volume = XFLOAT_DATA (attrs[SOUND_VOLUME]) * 100;
args[0] = Qplay_sound_functions;
args[1] = sound;
Frun_hook_with_args (2, args);
/* There is only one type of device we currently support, the VOX
sound driver. Set up the device interface functions for that
device. */
vox_init (&sd);
/* Open the device. */
sd.open (&sd);
/* Play the sound. */
s.play (&s, &sd);
/* Close the input file, if any. */
if (!STRINGP (s.data))
{
emacs_close (s.fd);
s.fd = -1;
}
/* Close the device. */
sd.close (&sd);
/* Clean up. */
current_sound_device = NULL;
current_sound = NULL;
UNGCPRO;
#else /* WINDOWSNT */
lo_file=Fexpand_file_name (attrs[SOUND_FILE], Qnil);