diff src/sound.c @ 17131:be5a5cfc991a v8.1.1565

patch 8.1.1565: MS-Windows: no sound support commit https://github.com/vim/vim/commit/9b283523f2f75b45feef902b8713808e883d9c19 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 17 22:19:33 2019 +0200 patch 8.1.1565: MS-Windows: no sound support Problem: MS-Windows: no sound support. Solution: Add sound support for MS-Windows. (Yasuhiro Matsumoto, Ken Takata, closes #4522)
author Bram Moolenaar <Bram@vim.org>
date Mon, 17 Jun 2019 22:30:06 +0200
parents 905e1b154058
children c08a3c552c1d
line wrap: on
line diff
--- a/src/sound.c
+++ b/src/sound.c
@@ -13,17 +13,18 @@
 
 #include "vim.h"
 
-#if (defined(FEAT_SOUND) && defined(HAVE_CANBERRA)) || defined(PROTO)
-
-#include <canberra.h>
+#if defined(FEAT_SOUND) || defined(PROTO)
 
 static long	    sound_id = 0;
-static ca_context   *context = NULL;
 
 typedef struct soundcb_S soundcb_T;
 
 struct soundcb_S {
     callback_T	snd_callback;
+#ifdef MSWIN
+    MCIDEVICEID	snd_device_id;
+    long	snd_id;
+#endif
     soundcb_T	*snd_next;
 };
 
@@ -75,6 +76,15 @@ delete_sound_callback(soundcb_T *soundcb
 	}
 }
 
+#if defined(HAVE_CANBERRA) || defined(PROTO)
+
+/*
+ * Sound implementation for Linux/Unix/Mac using libcanberra.
+ */
+# include <canberra.h>
+
+static ca_context   *context = NULL;
+
     static void
 sound_callback(
 	ca_context  *c UNUSED,
@@ -188,7 +198,7 @@ f_sound_clear(typval_T *argvars UNUSED, 
     }
 }
 
-#if defined(EXITFREE) || defined(PROTO)
+# if defined(EXITFREE) || defined(PROTO)
     void
 sound_free(void)
 {
@@ -197,6 +207,178 @@ sound_free(void)
     while (first_callback != NULL)
 	delete_sound_callback(first_callback);
 }
-#endif
+# endif
+
+#elif defined(MSWIN)
+
+/*
+ * Sound implementation for MS-Windows.
+ */
+
+static HWND g_hWndSound = NULL;
+
+    static LRESULT CALLBACK
+sound_wndproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    soundcb_T	*p;
+
+    switch (message)
+    {
+	case MM_MCINOTIFY:
+	    for (p = first_callback; p != NULL; p = p->snd_next)
+		if (p->snd_device_id == (MCIDEVICEID) lParam)
+		{
+		    typval_T	argv[3];
+		    typval_T	rettv;
+		    int		dummy;
+		    char	buf[32];
+
+		    vim_snprintf(buf, sizeof(buf), "close sound%06ld",
+								p->snd_id);
+		    mciSendString(buf, NULL, 0, 0);
+
+		    argv[0].v_type = VAR_NUMBER;
+		    argv[0].vval.v_number = p->snd_id;
+		    argv[1].v_type = VAR_NUMBER;
+		    argv[1].vval.v_number =
+					wParam == MCI_NOTIFY_SUCCESSFUL ? 0
+				      : wParam == MCI_NOTIFY_ABORTED ? 1 : 2;
+		    argv[2].v_type = VAR_UNKNOWN;
+
+		    call_callback(&p->snd_callback, -1,
+			    &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE, NULL);
+		    clear_tv(&rettv);
+
+		    delete_sound_callback(p);
+		    redraw_after_callback(TRUE);
+
+		}
+	    break;
+    }
+
+    return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+    static HWND
+sound_window()
+{
+    if (g_hWndSound == NULL)
+    {
+	LPCSTR clazz = "VimSound";
+	WNDCLASS wndclass = {
+	    0, sound_wndproc, 0, 0, g_hinst, NULL, 0, 0, NULL, clazz };
+	RegisterClass(&wndclass);
+	g_hWndSound = CreateWindow(clazz, NULL, 0, 0, 0, 0, 0,
+		HWND_MESSAGE, NULL, g_hinst, NULL);
+    }
+
+    return g_hWndSound;
+}
+
+    void
+f_sound_playevent(typval_T *argvars, typval_T *rettv)
+{
+    WCHAR	    *wp;
+
+    rettv->v_type = VAR_NUMBER;
+    rettv->vval.v_number = 0;
+
+    wp = enc_to_utf16(tv_get_string(&argvars[0]), NULL);
+    if (wp == NULL)
+	return;
+
+    PlaySoundW(wp, NULL, SND_ASYNC | SND_ALIAS);
+    free(wp);
+
+    rettv->vval.v_number = ++sound_id;
+}
 
-#endif  // FEAT_SOUND && HAVE_CANBERRA
+    void
+f_sound_playfile(typval_T *argvars, typval_T *rettv)
+{
+    long	newid = sound_id + 1;
+    size_t	len;
+    char_u	*p, *esc;
+    WCHAR	*wp;
+    soundcb_T	*soundcb;
+    char	buf[32];
+    MCIERROR	err;
+
+    rettv->v_type = VAR_NUMBER;
+    rettv->vval.v_number = 0;
+
+    esc = vim_strsave_shellescape(tv_get_string(&argvars[0]), FALSE, FALSE);
+
+    len = STRLEN(esc) + 5 + 18 + 1;
+    p = alloc(len);
+    if (p == NULL)
+    {
+	free(esc);
+	return;
+    }
+    vim_snprintf((char *)p, len, "open %s alias sound%06ld", esc, newid);
+    free(esc);
+
+    wp = enc_to_utf16((char_u *)p, NULL);
+    free(p);
+    if (wp == NULL)
+	return;
+
+    err = mciSendStringW(wp, NULL, 0, sound_window());
+    free(wp);
+    if (err != 0)
+	return;
+
+    vim_snprintf(buf, sizeof(buf), "play sound%06ld notify", newid);
+    err = mciSendString(buf, NULL, 0, sound_window());
+    if (err != 0)
+	goto failure;
+
+    sound_id = newid;
+    rettv->vval.v_number = sound_id;
+
+    soundcb = get_sound_callback(&argvars[1]);
+    if (soundcb != NULL)
+    {
+	vim_snprintf(buf, sizeof(buf), "sound%06ld", newid);
+	soundcb->snd_id = newid;
+	soundcb->snd_device_id = mciGetDeviceID(buf);
+    }
+    return;
+
+failure:
+    vim_snprintf(buf, sizeof(buf), "close sound%06ld", newid);
+    mciSendString(buf, NULL, 0, NULL);
+}
+
+    void
+f_sound_stop(typval_T *argvars, typval_T *rettv UNUSED)
+{
+    long    id = tv_get_number(&argvars[0]);
+    char    buf[32];
+
+    vim_snprintf(buf, sizeof(buf), "stop sound%06ld", id);
+    mciSendString(buf, NULL, 0, NULL);
+}
+
+    void
+f_sound_clear(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
+{
+    PlaySound(NULL, NULL, 0);
+    mciSendString("close all", NULL, 0, NULL);
+}
+
+# if defined(EXITFREE)
+    void
+sound_free(void)
+{
+    CloseWindow(g_hWndSound);
+
+    while (first_callback != NULL)
+	delete_sound_callback(first_callback);
+}
+# endif
+
+#endif // MSWIN
+
+#endif  // FEAT_SOUND