Commit a7fc3ab8 authored by Eli Zaretskii's avatar Eli Zaretskii

Support playing on MS-Windows non-ASCII sound files using Unicode APIs.

 src/sound.c [WINDOWSNT]: Include w32common.h and mbstring.h.
 (SOUND_WARNING) [WINDOWSNT]: Include in do..while and improve the
 error message format.  Use message_with_string to have non-ASCII
 file names properly displayed.
 (do_play_sound) [WINDOWSNT]: Use Unicode APIs to play sound files
 when w32-unicode-filenames is non-nil, but not on Windows 9X,
 where these APIs are not available even in UNICOWS.DLL.  Improve
 the format of error messages and include the file name in them
 where appropriate.
 (Fplay_sound_internal) [WINDOWSNT]: Make the MS-Windows branch
 call play-sound-functions, per documentation.
 src/w32.c (w32_get_long_filename, w32_get_short_filename): Constify
 the input file name arguments.
 src/w32.h (w32_get_long_filename, w32_get_short_filename): Update
 prototypes.
parent edb0288b
2014-09-15 Eli Zaretskii <eliz@gnu.org>
* sound.c [WINDOWSNT]: Include w32common.h and mbstring.h.
(SOUND_WARNING) [WINDOWSNT]: Include in do..while and improve the
error message format. Use message_with_string to have non-ASCII
file names properly displayed.
(do_play_sound) [WINDOWSNT]: Use Unicode APIs to play sound files
when w32-unicode-filenames is non-nil, but not on Windows 9X,
where these APIs are not available even in UNICOWS.DLL. Improve
the format of error messages and include the file name in them
where appropriate.
(Fplay_sound_internal) [WINDOWSNT]: Make the MS-Windows branch
call play-sound-functions, per documentation.
* w32.c (w32_get_long_filename, w32_get_short_filename): Constify
the input file name arguments.
* w32.h (w32_get_long_filename, w32_get_short_filename): Update
prototypes.
2014-09-15 Dmitry Antipov <dmantipov@yandex.ru>
If USE_LOCAL_ALLOCATORS, allocate some Lisp objects on stack.
......
......@@ -86,10 +86,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
/* 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 */
......@@ -1207,38 +1209,83 @@ alsa_init (struct sound_device *sd)
/* 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];
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);
/* 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;
}
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;
}
......@@ -1252,44 +1299,47 @@ do_play_sound (const char *psz_file, unsigned long ui_volume)
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;
......@@ -1307,13 +1357,11 @@ Internal use only, use `play-sound' instead. */)
{
Lisp_Object attrs[SOUND_ATTR_SENTINEL];
ptrdiff_t count = SPECPDL_INDEX ();
#ifndef WINDOWSNT
Lisp_Object file;
struct gcpro gcpro1, gcpro2;
Lisp_Object args[2];
#else /* WINDOWSNT */
Lisp_Object lo_file;
struct gcpro gcpro1, gcpro2;
#ifdef WINDOWSNT
unsigned long ui_volume_tmp = UINT_MAX;
unsigned long ui_volume = UINT_MAX;
#endif /* WINDOWSNT */
......@@ -1386,11 +1434,8 @@ Internal use only, use `play-sound' instead. */)
#else /* WINDOWSNT */
lo_file = Fexpand_file_name (attrs[SOUND_FILE], Vdata_directory);
lo_file = ENCODE_FILE (lo_file);
/* Since UNICOWS.DLL includes only a stub for mciSendStringW, we
need to encode the file in the ANSI codepage. */
lo_file = ansi_encode_filename (lo_file);
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]);
......@@ -1399,6 +1444,13 @@ Internal use only, use `play-sound' instead. */)
{
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.
......@@ -1412,7 +1464,9 @@ Internal use only, use `play-sound' instead. */)
{
ui_volume = ui_volume_tmp * (UINT_MAX / 100);
}
do_play_sound (SDATA (lo_file), ui_volume);
(void)do_play_sound (SSDATA (file), ui_volume);
UNGCPRO;
#endif /* WINDOWSNT */
......
......@@ -2294,7 +2294,7 @@ get_long_basename (char * name, char * buf, int size)
/* Get long name for file, if possible (assumed to be absolute). */
BOOL
w32_get_long_filename (char * name, char * buf, int size)
w32_get_long_filename (const char * name, char * buf, int size)
{
char * o = buf;
char * p;
......@@ -2345,7 +2345,7 @@ w32_get_long_filename (char * name, char * buf, int size)
}
unsigned int
w32_get_short_filename (char * name, char * buf, int size)
w32_get_short_filename (const char * name, char * buf, int size)
{
if (w32_unicode_filenames)
{
......
......@@ -144,10 +144,10 @@ extern char * w32_strerror (int error_no);
extern int w32_valid_pointer_p (void *, int);
/* Get long (aka "true") form of file name, if it exists. */
extern BOOL w32_get_long_filename (char * name, char * buf, int size);
extern BOOL w32_get_long_filename (const char * name, char * buf, int size);
/* Get the short (a.k.a. "8+3") form of a file name. */
extern unsigned int w32_get_short_filename (char *, char *, int);
extern unsigned int w32_get_short_filename (const char *, char *, int);
/* Prepare our standard handles for proper inheritance by child processes. */
extern void prepare_standard_handles (int in, int out,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment